<!DOCTYPE html>
<html lang="en-US" dir="ltr">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>高可用⭐ | VitePress</title>
    <meta name="description" content="A VitePress site">
    <link rel="preload stylesheet" href="/notebook/assets/style.3dbfd0c2.css" as="style">
    
    <script type="module" src="/notebook/assets/app.8aaa4cbe.js"></script>
    <link rel="preload" href="/notebook/assets/inter-roman-latin.2ed14f66.woff2" as="font" type="font/woff2" crossorigin="">
    <link rel="modulepreload" href="/notebook/assets/chunks/framework.1336c4e5.js">
    <link rel="modulepreload" href="/notebook/assets/chunks/theme.20cddc0c.js">
    <link rel="modulepreload" href="/notebook/assets/三高_高可用.md.323840c5.lean.js">
    <script id="check-dark-light">(()=>{const e=localStorage.getItem("vitepress-theme-appearance")||"",a=window.matchMedia("(prefers-color-scheme: dark)").matches;(!e||e==="auto"?a:e==="dark")&&document.documentElement.classList.add("dark")})();</script>
  </head>
  <body>
    <div id="app"><div class="Layout" data-v-255ec12d><!--[--><!--]--><!--[--><span tabindex="-1" data-v-ae3e3f51></span><a href="#VPContent" class="VPSkipLink visually-hidden" data-v-ae3e3f51> Skip to content </a><!--]--><!----><header class="VPNav" data-v-255ec12d data-v-7e5bc4a5><div class="VPNavBar has-sidebar" data-v-7e5bc4a5 data-v-0937f67c><div class="container" data-v-0937f67c><div class="title" data-v-0937f67c><div class="VPNavBarTitle has-sidebar" data-v-0937f67c data-v-86d1bed8><a class="title" href="/notebook/" data-v-86d1bed8><!--[--><!--]--><!--[--><img class="VPImage logo" src="/notebook/Vue.png" alt data-v-8426fc1a><!--]--><!--[-->任硕的文档<!--]--><!--[--><!--]--></a></div></div><div class="content" data-v-0937f67c><div class="curtain" data-v-0937f67c></div><div class="content-body" data-v-0937f67c><!--[--><!--]--><div class="VPNavBarSearch search" style="--vp-meta-key:&#39;Meta&#39;;" data-v-0937f67c><!--[--><!----><div id="docsearch"><button type="button" class="DocSearch DocSearch-Button" aria-label="Search"><span class="DocSearch-Button-Container"><svg class="DocSearch-Search-Icon" width="20" height="20" viewBox="0 0 20 20" aria-label="search icon"><path d="M14.386 14.386l4.0877 4.0877-4.0877-4.0877c-2.9418 2.9419-7.7115 2.9419-10.6533 0-2.9419-2.9418-2.9419-7.7115 0-10.6533 2.9418-2.9419 7.7115-2.9419 10.6533 0 2.9419 2.9418 2.9419 7.7115 0 10.6533z" stroke="currentColor" fill="none" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round"></path></svg><span class="DocSearch-Button-Placeholder">Search</span></span><span class="DocSearch-Button-Keys"><kbd class="DocSearch-Button-Key"></kbd><kbd class="DocSearch-Button-Key">K</kbd></span></button></div><!--]--></div><nav aria-labelledby="main-nav-aria-label" class="VPNavBarMenu menu" data-v-0937f67c data-v-7f418b0f><span id="main-nav-aria-label" class="visually-hidden" data-v-7f418b0f>Main Navigation</span><!--[--><!--[--><div class="VPFlyout VPNavBarMenuGroup" data-v-7f418b0f data-v-a7b5672a><button type="button" class="button" aria-haspopup="true" aria-expanded="false" data-v-a7b5672a><span class="text" data-v-a7b5672a><!----><span data-v-a7b5672a>Java学前端</span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="text-icon" data-v-a7b5672a><path d="M12,16c-0.3,0-0.5-0.1-0.7-0.3l-6-6c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l5.3,5.3l5.3-5.3c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-6,6C12.5,15.9,12.3,16,12,16z"></path></svg></span></button><div class="menu" data-v-a7b5672a><div class="VPMenu" data-v-a7b5672a data-v-e7ea1737><div class="items" data-v-e7ea1737><!--[--><!--[--><div class="VPMenuGroup" data-v-e7ea1737 data-v-69e747b5><!----><!--[--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/Java%E5%AD%A6%E5%89%8D%E7%AB%AF/HTML+JS.html" data-v-2f2cfafc><!--[-->HTML+JS<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/Java%E5%AD%A6%E5%89%8D%E7%AB%AF/CSS.html" data-v-2f2cfafc><!--[-->CSS<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/Java%E5%AD%A6%E5%89%8D%E7%AB%AF/Vue2+%E7%BB%84%E4%BB%B6.html" data-v-2f2cfafc><!--[-->Vue2+组件<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/Java%E5%AD%A6%E5%89%8D%E7%AB%AF/Vue3+%E7%BB%84%E4%BB%B6.html" data-v-2f2cfafc><!--[-->Vue3+组件<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/Java%E5%AD%A6%E5%89%8D%E7%AB%AF/React.html" data-v-2f2cfafc><!--[-->React<!--]--></a></div><!--]--><!--]--></div><!--]--><!--]--></div><!--[--><!--]--></div></div></div><!--]--><!--[--><div class="VPFlyout VPNavBarMenuGroup" data-v-7f418b0f data-v-a7b5672a><button type="button" class="button" aria-haspopup="true" aria-expanded="false" data-v-a7b5672a><span class="text" data-v-a7b5672a><!----><span data-v-a7b5672a>软件测试</span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="text-icon" data-v-a7b5672a><path d="M12,16c-0.3,0-0.5-0.1-0.7-0.3l-6-6c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l5.3,5.3l5.3-5.3c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-6,6C12.5,15.9,12.3,16,12,16z"></path></svg></span></button><div class="menu" data-v-a7b5672a><div class="VPMenu" data-v-a7b5672a data-v-e7ea1737><div class="items" data-v-e7ea1737><!--[--><!--[--><div class="VPMenuGroup" data-v-e7ea1737 data-v-69e747b5><!----><!--[--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/%E8%BD%AF%E4%BB%B6%E6%B5%8B%E8%AF%95/%E6%B5%8B%E8%AF%95%E5%9F%BA%E7%A1%80.html" data-v-2f2cfafc><!--[-->测试基础<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/%E8%BD%AF%E4%BB%B6%E6%B5%8B%E8%AF%95/%E5%8E%8B%E5%8A%9B%E6%B5%8B%E8%AF%95.html" data-v-2f2cfafc><!--[-->压力测试<!--]--></a></div><!--]--><!--]--></div><!--]--><!--]--></div><!--[--><!--]--></div></div></div><!--]--><!--[--><div class="VPFlyout VPNavBarMenuGroup" data-v-7f418b0f data-v-a7b5672a><button type="button" class="button" aria-haspopup="true" aria-expanded="false" data-v-a7b5672a><span class="text" data-v-a7b5672a><!----><span data-v-a7b5672a>多线程</span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="text-icon" data-v-a7b5672a><path d="M12,16c-0.3,0-0.5-0.1-0.7-0.3l-6-6c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l5.3,5.3l5.3-5.3c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-6,6C12.5,15.9,12.3,16,12,16z"></path></svg></span></button><div class="menu" data-v-a7b5672a><div class="VPMenu" data-v-a7b5672a data-v-e7ea1737><div class="items" data-v-e7ea1737><!--[--><!--[--><div class="VPMenuGroup" data-v-e7ea1737 data-v-69e747b5><!----><!--[--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/%E5%B9%B6%E5%8F%91%20&amp;%20%E5%A4%9A%E7%BA%BF%E7%A8%8B/%E5%9F%BA%E7%A1%80%E7%AF%87.html" data-v-2f2cfafc><!--[-->基础篇<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/%E5%B9%B6%E5%8F%91%20&amp;%20%E5%A4%9A%E7%BA%BF%E7%A8%8B/%E5%B9%B6%E5%8F%91%E5%AE%8C%E5%96%84.html" data-v-2f2cfafc><!--[-->进阶篇<!--]--></a></div><!--]--><!--]--></div><!--]--><!--]--></div><!--[--><!--]--></div></div></div><!--]--><!--[--><div class="VPFlyout VPNavBarMenuGroup" data-v-7f418b0f data-v-a7b5672a><button type="button" class="button" aria-haspopup="true" aria-expanded="false" data-v-a7b5672a><span class="text" data-v-a7b5672a><!----><span data-v-a7b5672a>开发工具</span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="text-icon" data-v-a7b5672a><path d="M12,16c-0.3,0-0.5-0.1-0.7-0.3l-6-6c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l5.3,5.3l5.3-5.3c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-6,6C12.5,15.9,12.3,16,12,16z"></path></svg></span></button><div class="menu" data-v-a7b5672a><div class="VPMenu" data-v-a7b5672a data-v-e7ea1737><div class="items" data-v-e7ea1737><!--[--><!--[--><div class="VPMenuGroup" data-v-e7ea1737 data-v-69e747b5><!----><!--[--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/IDEA/Chrome.html" data-v-2f2cfafc><!--[-->Chrome<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/IDEA/IDEA%E5%9F%BA%E7%A1%80.html" data-v-2f2cfafc><!--[-->IDEA基础<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/IDEA/IDEA%E6%8F%92%E4%BB%B6.html" data-v-2f2cfafc><!--[-->IDEA插件<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/IDEA/VS%20Code.html" data-v-2f2cfafc><!--[-->VS Code<!--]--></a></div><!--]--><!--]--></div><!--]--><!--]--></div><!--[--><!--]--></div></div></div><!--]--><!--[--><div class="VPFlyout VPNavBarMenuGroup" data-v-7f418b0f data-v-a7b5672a><button type="button" class="button" aria-haspopup="true" aria-expanded="false" data-v-a7b5672a><span class="text" data-v-a7b5672a><!----><span data-v-a7b5672a>消息中间件</span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="text-icon" data-v-a7b5672a><path d="M12,16c-0.3,0-0.5-0.1-0.7-0.3l-6-6c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l5.3,5.3l5.3-5.3c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-6,6C12.5,15.9,12.3,16,12,16z"></path></svg></span></button><div class="menu" data-v-a7b5672a><div class="VPMenu" data-v-a7b5672a data-v-e7ea1737><div class="items" data-v-e7ea1737><!--[--><!--[--><div class="VPMenuGroup" data-v-e7ea1737 data-v-69e747b5><!----><!--[--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/%E6%B6%88%E6%81%AF%E4%B8%AD%E9%97%B4%E4%BB%B6/RabbitMQ.html" data-v-2f2cfafc><!--[-->RabbitMQ<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/%E6%B6%88%E6%81%AF%E4%B8%AD%E9%97%B4%E4%BB%B6/RocketMQ.html" data-v-2f2cfafc><!--[-->RocketMQ<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/%E6%B6%88%E6%81%AF%E4%B8%AD%E9%97%B4%E4%BB%B6/Kafka.html" data-v-2f2cfafc><!--[-->Kafka<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/%E6%B6%88%E6%81%AF%E4%B8%AD%E9%97%B4%E4%BB%B6/Canal.html" data-v-2f2cfafc><!--[-->Canal<!--]--></a></div><!--]--><!--]--></div><!--]--><!--]--></div><!--[--><!--]--></div></div></div><!--]--><!--]--></nav><!----><div class="VPNavBarAppearance appearance" data-v-0937f67c data-v-f6a63727><button class="VPSwitch VPSwitchAppearance" type="button" role="switch" title="toggle dark mode" aria-checked="false" data-v-f6a63727 data-v-82b282f1 data-v-f3c41672><span class="check" data-v-f3c41672><span class="icon" data-v-f3c41672><!--[--><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="sun" data-v-82b282f1><path d="M12,18c-3.3,0-6-2.7-6-6s2.7-6,6-6s6,2.7,6,6S15.3,18,12,18zM12,8c-2.2,0-4,1.8-4,4c0,2.2,1.8,4,4,4c2.2,0,4-1.8,4-4C16,9.8,14.2,8,12,8z"></path><path d="M12,4c-0.6,0-1-0.4-1-1V1c0-0.6,0.4-1,1-1s1,0.4,1,1v2C13,3.6,12.6,4,12,4z"></path><path d="M12,24c-0.6,0-1-0.4-1-1v-2c0-0.6,0.4-1,1-1s1,0.4,1,1v2C13,23.6,12.6,24,12,24z"></path><path d="M5.6,6.6c-0.3,0-0.5-0.1-0.7-0.3L3.5,4.9c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l1.4,1.4c0.4,0.4,0.4,1,0,1.4C6.2,6.5,5.9,6.6,5.6,6.6z"></path><path d="M19.8,20.8c-0.3,0-0.5-0.1-0.7-0.3l-1.4-1.4c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l1.4,1.4c0.4,0.4,0.4,1,0,1.4C20.3,20.7,20,20.8,19.8,20.8z"></path><path d="M3,13H1c-0.6,0-1-0.4-1-1s0.4-1,1-1h2c0.6,0,1,0.4,1,1S3.6,13,3,13z"></path><path d="M23,13h-2c-0.6,0-1-0.4-1-1s0.4-1,1-1h2c0.6,0,1,0.4,1,1S23.6,13,23,13z"></path><path d="M4.2,20.8c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l1.4-1.4c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-1.4,1.4C4.7,20.7,4.5,20.8,4.2,20.8z"></path><path d="M18.4,6.6c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l1.4-1.4c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-1.4,1.4C18.9,6.5,18.6,6.6,18.4,6.6z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="moon" data-v-82b282f1><path d="M12.1,22c-0.3,0-0.6,0-0.9,0c-5.5-0.5-9.5-5.4-9-10.9c0.4-4.8,4.2-8.6,9-9c0.4,0,0.8,0.2,1,0.5c0.2,0.3,0.2,0.8-0.1,1.1c-2,2.7-1.4,6.4,1.3,8.4c2.1,1.6,5,1.6,7.1,0c0.3-0.2,0.7-0.3,1.1-0.1c0.3,0.2,0.5,0.6,0.5,1c-0.2,2.7-1.5,5.1-3.6,6.8C16.6,21.2,14.4,22,12.1,22zM9.3,4.4c-2.9,1-5,3.6-5.2,6.8c-0.4,4.4,2.8,8.3,7.2,8.7c2.1,0.2,4.2-0.4,5.8-1.8c1.1-0.9,1.9-2.1,2.4-3.4c-2.5,0.9-5.3,0.5-7.5-1.1C9.2,11.4,8.1,7.7,9.3,4.4z"></path></svg><!--]--></span></span></button></div><div class="VPSocialLinks VPNavBarSocialLinks social-links" data-v-0937f67c data-v-0394ad82 data-v-7bc22406><!--[--><a class="VPSocialLink no-icon" href="https://github.com/renshuo123/renshuo123.github.io" aria-label="github" target="_blank" rel="noopener" data-v-7bc22406 data-v-f80f8133><svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>GitHub</title><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></a><a class="VPSocialLink no-icon" href="#" aria-label="twitter" target="_blank" rel="noopener" data-v-7bc22406 data-v-f80f8133><svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Twitter</title><path d="M23.953 4.57a10 10 0 01-2.825.775 4.958 4.958 0 002.163-2.723c-.951.555-2.005.959-3.127 1.184a4.92 4.92 0 00-8.384 4.482C7.69 8.095 4.067 6.13 1.64 3.162a4.822 4.822 0 00-.666 2.475c0 1.71.87 3.213 2.188 4.096a4.904 4.904 0 01-2.228-.616v.06a4.923 4.923 0 003.946 4.827 4.996 4.996 0 01-2.212.085 4.936 4.936 0 004.604 3.417 9.867 9.867 0 01-6.102 2.105c-.39 0-.779-.023-1.17-.067a13.995 13.995 0 007.557 2.209c9.053 0 13.998-7.496 13.998-13.985 0-.21 0-.42-.015-.63A9.935 9.935 0 0024 4.59z"/></svg></a><a class="VPSocialLink no-icon" href="https://github.com/" aria-label target="_blank" rel="noopener" data-v-7bc22406 data-v-f80f8133><svg t="1676028692954" class="icon" ...</path></svg></a><!--]--></div><div class="VPFlyout VPNavBarExtra extra" data-v-0937f67c data-v-40855f84 data-v-a7b5672a><button type="button" class="button" aria-haspopup="true" aria-expanded="false" aria-label="extra navigation" data-v-a7b5672a><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="icon" data-v-a7b5672a><circle cx="12" cy="12" r="2"></circle><circle cx="19" cy="12" r="2"></circle><circle cx="5" cy="12" r="2"></circle></svg></button><div class="menu" data-v-a7b5672a><div class="VPMenu" data-v-a7b5672a data-v-e7ea1737><!----><!--[--><!--[--><!----><div class="group" data-v-40855f84><div class="item appearance" data-v-40855f84><p class="label" data-v-40855f84>Appearance</p><div class="appearance-action" data-v-40855f84><button class="VPSwitch VPSwitchAppearance" type="button" role="switch" title="toggle dark mode" aria-checked="false" data-v-40855f84 data-v-82b282f1 data-v-f3c41672><span class="check" data-v-f3c41672><span class="icon" data-v-f3c41672><!--[--><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="sun" data-v-82b282f1><path d="M12,18c-3.3,0-6-2.7-6-6s2.7-6,6-6s6,2.7,6,6S15.3,18,12,18zM12,8c-2.2,0-4,1.8-4,4c0,2.2,1.8,4,4,4c2.2,0,4-1.8,4-4C16,9.8,14.2,8,12,8z"></path><path d="M12,4c-0.6,0-1-0.4-1-1V1c0-0.6,0.4-1,1-1s1,0.4,1,1v2C13,3.6,12.6,4,12,4z"></path><path d="M12,24c-0.6,0-1-0.4-1-1v-2c0-0.6,0.4-1,1-1s1,0.4,1,1v2C13,23.6,12.6,24,12,24z"></path><path d="M5.6,6.6c-0.3,0-0.5-0.1-0.7-0.3L3.5,4.9c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l1.4,1.4c0.4,0.4,0.4,1,0,1.4C6.2,6.5,5.9,6.6,5.6,6.6z"></path><path d="M19.8,20.8c-0.3,0-0.5-0.1-0.7-0.3l-1.4-1.4c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l1.4,1.4c0.4,0.4,0.4,1,0,1.4C20.3,20.7,20,20.8,19.8,20.8z"></path><path d="M3,13H1c-0.6,0-1-0.4-1-1s0.4-1,1-1h2c0.6,0,1,0.4,1,1S3.6,13,3,13z"></path><path d="M23,13h-2c-0.6,0-1-0.4-1-1s0.4-1,1-1h2c0.6,0,1,0.4,1,1S23.6,13,23,13z"></path><path d="M4.2,20.8c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l1.4-1.4c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-1.4,1.4C4.7,20.7,4.5,20.8,4.2,20.8z"></path><path d="M18.4,6.6c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l1.4-1.4c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-1.4,1.4C18.9,6.5,18.6,6.6,18.4,6.6z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="moon" data-v-82b282f1><path d="M12.1,22c-0.3,0-0.6,0-0.9,0c-5.5-0.5-9.5-5.4-9-10.9c0.4-4.8,4.2-8.6,9-9c0.4,0,0.8,0.2,1,0.5c0.2,0.3,0.2,0.8-0.1,1.1c-2,2.7-1.4,6.4,1.3,8.4c2.1,1.6,5,1.6,7.1,0c0.3-0.2,0.7-0.3,1.1-0.1c0.3,0.2,0.5,0.6,0.5,1c-0.2,2.7-1.5,5.1-3.6,6.8C16.6,21.2,14.4,22,12.1,22zM9.3,4.4c-2.9,1-5,3.6-5.2,6.8c-0.4,4.4,2.8,8.3,7.2,8.7c2.1,0.2,4.2-0.4,5.8-1.8c1.1-0.9,1.9-2.1,2.4-3.4c-2.5,0.9-5.3,0.5-7.5-1.1C9.2,11.4,8.1,7.7,9.3,4.4z"></path></svg><!--]--></span></span></button></div></div></div><div class="group" data-v-40855f84><div class="item social-links" data-v-40855f84><div class="VPSocialLinks social-links-list" data-v-40855f84 data-v-7bc22406><!--[--><a class="VPSocialLink no-icon" href="https://github.com/renshuo123/renshuo123.github.io" aria-label="github" target="_blank" rel="noopener" data-v-7bc22406 data-v-f80f8133><svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>GitHub</title><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></a><a class="VPSocialLink no-icon" href="#" aria-label="twitter" target="_blank" rel="noopener" data-v-7bc22406 data-v-f80f8133><svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Twitter</title><path d="M23.953 4.57a10 10 0 01-2.825.775 4.958 4.958 0 002.163-2.723c-.951.555-2.005.959-3.127 1.184a4.92 4.92 0 00-8.384 4.482C7.69 8.095 4.067 6.13 1.64 3.162a4.822 4.822 0 00-.666 2.475c0 1.71.87 3.213 2.188 4.096a4.904 4.904 0 01-2.228-.616v.06a4.923 4.923 0 003.946 4.827 4.996 4.996 0 01-2.212.085 4.936 4.936 0 004.604 3.417 9.867 9.867 0 01-6.102 2.105c-.39 0-.779-.023-1.17-.067a13.995 13.995 0 007.557 2.209c9.053 0 13.998-7.496 13.998-13.985 0-.21 0-.42-.015-.63A9.935 9.935 0 0024 4.59z"/></svg></a><a class="VPSocialLink no-icon" href="https://github.com/" aria-label target="_blank" rel="noopener" data-v-7bc22406 data-v-f80f8133><svg t="1676028692954" class="icon" ...</path></svg></a><!--]--></div></div></div><!--]--><!--]--></div></div></div><!--[--><!--]--><button type="button" class="VPNavBarHamburger hamburger" aria-label="mobile navigation" aria-expanded="false" aria-controls="VPNavScreen" data-v-0937f67c data-v-e5dd9c1c><span class="container" data-v-e5dd9c1c><span class="top" data-v-e5dd9c1c></span><span class="middle" data-v-e5dd9c1c></span><span class="bottom" data-v-e5dd9c1c></span></span></button></div></div></div></div><!----></header><div class="VPLocalNav reached-top" data-v-255ec12d data-v-5cfd5582><button class="menu" aria-expanded="false" aria-controls="VPSidebarNav" data-v-5cfd5582><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="menu-icon" data-v-5cfd5582><path d="M17,11H3c-0.6,0-1-0.4-1-1s0.4-1,1-1h14c0.6,0,1,0.4,1,1S17.6,11,17,11z"></path><path d="M21,7H3C2.4,7,2,6.6,2,6s0.4-1,1-1h18c0.6,0,1,0.4,1,1S21.6,7,21,7z"></path><path d="M21,15H3c-0.6,0-1-0.4-1-1s0.4-1,1-1h18c0.6,0,1,0.4,1,1S21.6,15,21,15z"></path><path d="M17,19H3c-0.6,0-1-0.4-1-1s0.4-1,1-1h14c0.6,0,1,0.4,1,1S17.6,19,17,19z"></path></svg><span class="menu-text" data-v-5cfd5582>Menu</span></button><div class="VPLocalNavOutlineDropdown" style="--vp-vh:0px;" data-v-5cfd5582 data-v-18201f51><button data-v-18201f51>Return to top</button><!----></div></div><aside class="VPSidebar" data-v-255ec12d data-v-845b8fc6><div class="curtain" data-v-845b8fc6></div><nav class="nav" id="VPSidebarNav" aria-labelledby="sidebar-aria-label" tabindex="-1" data-v-845b8fc6><span class="visually-hidden" id="sidebar-aria-label" data-v-845b8fc6> Sidebar Navigation </span><!--[--><!--]--><!--[--><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>Java</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Java/Java%E5%9F%BA%E7%A1%80.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Java基础</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Java/Java%E6%96%B0%E7%89%B9%E6%80%A7.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Java新特性</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Java/Java%E8%BF%9B%E9%98%B6.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Java进阶</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Java/Java%E9%9B%86%E5%90%88.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Java集合</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Java/Java%E9%AB%98%E7%BA%A7.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Java高级</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>Linux</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Linux/Linux%E5%9F%BA%E7%A1%80.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Linux基础</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Linux/Linux%E8%BF%9B%E9%98%B6.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Linux新特性</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Linux/Shell.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Shell脚本</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Linux/%E5%AE%9E%E7%94%A8%E8%84%9A%E6%9C%AC.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>实用脚本</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Linux/%E8%BD%AF%E4%BB%B6%E9%83%A8%E7%BD%B2.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>软件部署</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>Nginx</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Nginx/%E5%9F%BA%E7%A1%80%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>基础篇</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Nginx/%E8%BF%9B%E9%98%B6%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>进阶篇</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Nginx/%E5%AE%9E%E6%88%98%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>实战篇</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Nginx/%E9%9D%A2%E8%AF%95%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>面试篇</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>SSM</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/SSM/Maven.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Maven</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/SSM/Spring.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Spring</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/SSM/SpringMVC.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>SpringMVC</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/SSM/SpringBatch.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>SpringBatch</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>SpringBoot</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/3%E3%80%81SpringBoot/%E5%9F%BA%E7%A1%80%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>基础篇</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/3%E3%80%81SpringBoot/%E5%BA%94%E7%94%A8%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>应用篇</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/3%E3%80%81SpringBoot/%E6%96%B0%E7%89%B9%E6%80%A7.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>新特性</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/3%E3%80%81SpringBoot/%E8%BF%90%E7%BB%B4&amp;%E5%8E%9F%E7%90%86.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>运维&原理</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>SpringCloud</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/4%E3%80%81%E5%BE%AE%E6%9C%8D%E5%8A%A1/%E8%BF%9B%E9%98%B6.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>SpringCloud</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/4%E3%80%81%E5%BE%AE%E6%9C%8D%E5%8A%A1/%E5%BF%85%E5%A4%87/Sentinel.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Sentinel</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>SpringSecurity</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/4%E3%80%81%E5%BE%AE%E6%9C%8D%E5%8A%A1/SpringSecurity/%E5%9F%BA%E7%A1%80%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>SpringSecurity基础篇</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/4%E3%80%81%E5%BE%AE%E6%9C%8D%E5%8A%A1/SpringSecurity/%E8%BF%9B%E9%98%B6%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>SpringSecurity进阶篇</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/4%E3%80%81%E5%BE%AE%E6%9C%8D%E5%8A%A1/SpringSecurity/%E9%AB%98%E7%BA%A7%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>SpringSecurity高级篇</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>Mybatis & MybatisPlus</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Mybatis&amp;MybatisPlus/Mybatis.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Mybatis</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Mybatis&amp;MybatisPlus/MybatisPlus.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>MybatisPlus</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Mybatis&amp;MybatisPlus/JPA.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>JPA</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>Git & ChatGPT</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/5%E3%80%81%E8%BF%90%E7%BB%B4/Git.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Git</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/5%E3%80%81%E8%BF%90%E7%BB%B4/Github.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Github</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/5%E3%80%81%E8%BF%90%E7%BB%B4/ChatGPT.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>ChatGPT</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/5%E3%80%81%E8%BF%90%E7%BB%B4/Jenkins.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Jenkins</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/5%E3%80%81%E8%BF%90%E7%BB%B4/Netty.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Netty</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>数据库</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><section class="VPSidebarItem level-1 collapsible collapsed" data-v-9b797284 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h3 class="text" data-v-9b797284>MySQL</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/MySQL/MySQL%E6%A0%B8%E5%BF%83/%E5%9F%BA%E7%A1%80.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>MySQL基础</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/MySQL/MySQL%E6%A0%B8%E5%BF%83/%E8%BF%9B%E9%98%B6.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>MySQL进阶</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/MySQL/MySQL%E6%A0%B8%E5%BF%83/%E4%BC%98%E5%8C%96.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>MySQL优化</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/MySQL/MySQL%E6%A0%B8%E5%BF%83/%E8%AE%BE%E8%AE%A1.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>MySQL设计</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/MySQL/MySQL%E6%A0%B8%E5%BF%83/%E8%BF%90%E7%BB%B4.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>MySQL运维</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/MySQL/%E5%88%86%E5%BA%93%E5%88%86%E8%A1%A8.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>分库分表</p><!--]--></a><!----></div><!----></div><!--]--></div></section><section class="VPSidebarItem level-1 collapsible collapsed" data-v-9b797284 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h3 class="text" data-v-9b797284>Redis</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/Redis/Redis%E5%9F%BA%E7%A1%80.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Redis基础</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/Redis/Redis%E4%BC%98%E5%8C%96.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Redis优化</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/Redis/Redis%E5%8E%9F%E7%90%86.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Redis原理</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/Redis/Redis%E9%AB%98%E7%BA%A7.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Redis高级</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/Redis/Redis%E5%AE%9E%E6%88%98.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Redis实战</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/Redis/%E6%9C%AC%E5%9C%B0%E7%BC%93%E5%AD%98.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>本地缓存</p><!--]--></a><!----></div><!----></div><!--]--></div></section><section class="VPSidebarItem level-1 collapsible collapsed" data-v-9b797284 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h3 class="text" data-v-9b797284>MongoDB</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/MongoDB/%E5%9F%BA%E7%A1%80.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>MongoDB基础</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/MongoDB/%E6%95%B4%E5%90%88.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>MongoDB进阶</p><!--]--></a><!----></div><!----></div><!--]--></div></section><section class="VPSidebarItem level-1 collapsible collapsed" data-v-9b797284 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h3 class="text" data-v-9b797284>ElasticSearch</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/ElasticSearch/1%E3%80%81ES%E5%9F%BA%E7%A1%80.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>ES基础</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/ElasticSearch/3%E3%80%81ES%E9%AB%98%E7%BA%A7.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>ES高级</p><!--]--></a><!----></div><!----></div><!--]--></div></section><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/influxdb.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>InfluxDB</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/Neo4j.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Neo4j</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible has-active" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>高并发 & 秒杀 & 分布式</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E4%B8%89%E9%AB%98/%E5%88%86%E5%B8%83%E5%BC%8F.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>分布式理论</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/4%E3%80%81%E5%BE%AE%E6%9C%8D%E5%8A%A1/%E5%BF%85%E5%A4%87/%E5%88%86%E5%B8%83%E5%BC%8F%E9%94%81.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>分布式锁</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E4%B8%89%E9%AB%98/%E7%A7%92%E6%9D%80.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>秒杀</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E4%B8%89%E9%AB%98/%E9%AB%98%E5%8F%AF%E7%94%A8.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>高可用</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E4%B8%89%E9%AB%98/%E9%AB%98%E5%B9%B6%E5%8F%91.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>高并发</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>云原生</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E4%BA%91%E5%8E%9F%E7%94%9F/Docker.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Docker</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E4%BA%91%E5%8E%9F%E7%94%9F/K8S.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>K8S</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>可视化 & 监控</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E5%8F%AF%E8%A7%86%E5%8C%96%20&amp;%20%E7%9B%91%E6%8E%A7/%E7%9B%91%E6%8E%A7%E5%9F%BA%E7%A1%80.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>监控基础</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E5%8F%AF%E8%A7%86%E5%8C%96%20&amp;%20%E7%9B%91%E6%8E%A7/%E7%9B%91%E6%8E%A7%E8%BF%9B%E9%98%B6.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>监控进阶</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E5%8F%AF%E8%A7%86%E5%8C%96%20&amp;%20%E7%9B%91%E6%8E%A7/%E5%8F%AF%E8%A7%86%E5%8C%96%E5%A4%A7%E5%B1%8F.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>可视化大屏</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E5%8F%AF%E8%A7%86%E5%8C%96%20&amp;%20%E7%9B%91%E6%8E%A7/Zabbix.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Zabbix</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>学前端</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><section class="VPSidebarItem level-1 collapsible collapsed" data-v-9b797284 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h3 class="text" data-v-9b797284>HTML+CSS</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/1%E3%80%81HTML+CSS/HTML%E5%9F%BA%E7%A1%80.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>HTML基础</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/1%E3%80%81HTML+CSS/CSS%E5%9F%BA%E7%A1%80.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>CSS基础</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/1%E3%80%81HTML+CSS/%E7%BD%91%E9%A1%B5%E8%BF%9B%E9%98%B6.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>网页进阶</p><!--]--></a><!----></div><!----></div><!--]--></div></section><section class="VPSidebarItem level-1 collapsible collapsed" data-v-9b797284 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h3 class="text" data-v-9b797284>JS+TS</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/2%E3%80%81JS+TS/JS%20%E5%9F%BA%E7%A1%80.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>JS基础</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/2%E3%80%81JS+TS/JS%20%E8%BF%9B%E9%98%B6.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>JS进阶</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/2%E3%80%81JS+TS/ES6%20%E5%9F%BA%E7%A1%80.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>ES6基础</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/2%E3%80%81JS+TS/ES6%20%E8%BF%9B%E9%98%B6.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>ES6进阶</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/2%E3%80%81JS+TS/TypeScript.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>TS基础</p><!--]--></a><!----></div><!----></div><!--]--></div></section><section class="VPSidebarItem level-1 collapsible collapsed" data-v-9b797284 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h3 class="text" data-v-9b797284>NodeJS</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/4%E3%80%81Node/%E5%9F%BA%E7%A1%80%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Node基础</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/4%E3%80%81Node/%E8%BF%9B%E9%98%B6%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Node进阶</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/4%E3%80%81Node/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>项目实战</p><!--]--></a><!----></div><!----></div><!--]--></div></section><section class="VPSidebarItem level-1 collapsible collapsed" data-v-9b797284 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h3 class="text" data-v-9b797284>Vue</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/3%E3%80%81Vue/Vue3/Vue3%E8%BF%9B%E9%98%B6.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Vue3进阶</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/3%E3%80%81Vue/Vue3/Vue3%E9%AB%98%E7%BA%A7.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Vue3高级</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/3%E3%80%81Vue/Vue3/Vue3%E6%96%B0%E8%AF%AD%E6%B3%95.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Vue3新语法</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/3%E3%80%81Vue/Vue2/Vue2%E9%A1%B9%E7%9B%AE.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>项目实战</p><!--]--></a><!----></div><!----></div><!--]--></div></section><section class="VPSidebarItem level-1 collapsible collapsed" data-v-9b797284 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h3 class="text" data-v-9b797284>小程序</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/5%E3%80%81%E5%B0%8F%E7%A8%8B%E5%BA%8F/%E5%BE%AE%E4%BF%A1%E5%B0%8F%E7%A8%8B%E5%BA%8F.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>小程序基础</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/5%E3%80%81%E5%B0%8F%E7%A8%8B%E5%BA%8F/%E5%B0%8F%E7%A8%8B%E5%BA%8F%E4%BC%98%E5%8C%96.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>小程序优化</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/5%E3%80%81%E5%B0%8F%E7%A8%8B%E5%BA%8F/uniapp.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>uniapp</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/5%E3%80%81%E5%B0%8F%E7%A8%8B%E5%BA%8F/%E5%B0%8F%E7%A8%8B%E5%BA%8F%E9%A1%B9%E7%9B%AE.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>项目实战</p><!--]--></a><!----></div><!----></div><!--]--></div></section><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>计算机基础</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%9F%BA%E7%A1%80/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/%E5%9F%BA%E7%A1%80%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>数据结构</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%9F%BA%E7%A1%80/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%9F%BA%E7%A1%80/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>操作系统</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%9F%BA%E7%A1%80/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/%E5%9F%BA%E7%A1%80%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>设计模式</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%9F%BA%E7%A1%80/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/%E7%BD%91%E7%BB%9C%E5%9F%BA%E7%A1%80.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>计算机网络</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%9F%BA%E7%A1%80/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/UML.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>UML</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%9F%BA%E7%A1%80/%E7%AE%97%E6%B3%95/LeetCode.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>LeetCode</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>项目实战</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><section class="VPSidebarItem level-1 collapsible collapsed" data-v-9b797284 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h3 class="text" data-v-9b797284>云尚办公</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98/%E4%BA%91%E5%B0%9A%E5%8A%9E%E5%85%AC/%E5%9F%BA%E7%A1%80%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>基础篇</p><!--]--></a><!----></div><!----></div><!--]--></div></section><section class="VPSidebarItem level-1 collapsible collapsed" data-v-9b797284 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h3 class="text" data-v-9b797284>小兔鲜</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98/%E5%B0%8F%E5%85%94%E9%B2%9C/%E5%9F%BA%E7%A1%80%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>基础篇</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98/%E5%B0%8F%E5%85%94%E9%B2%9C/%E8%BF%9B%E9%98%B6%E7%AF%871.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>进阶篇1</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98/%E5%B0%8F%E5%85%94%E9%B2%9C/%E8%BF%9B%E9%98%B6%E7%AF%872.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>进阶篇2</p><!--]--></a><!----></div><!----></div><!--]--></div></section><section class="VPSidebarItem level-1 collapsible collapsed" data-v-9b797284 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h3 class="text" data-v-9b797284>地图</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98/%E7%99%BE%E5%BA%A6%E5%9C%B0%E5%9B%BE/%E5%9F%BA%E7%A1%80%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>基础篇</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98/%E7%99%BE%E5%BA%A6%E5%9C%B0%E5%9B%BE/%E8%BF%9B%E9%98%B6%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>进阶篇</p><!--]--></a><!----></div><!----></div><!--]--></div></section><section class="VPSidebarItem level-1 collapsible collapsed" data-v-9b797284 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h3 class="text" data-v-9b797284>苍穹外卖</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98/%E8%8B%8D%E7%A9%B9%E5%A4%96%E5%8D%96/%E8%BF%9B%E9%98%B6%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>进阶篇</p><!--]--></a><!----></div><!----></div><!--]--></div></section><section class="VPSidebarItem level-1 collapsible collapsed" data-v-9b797284 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h3 class="text" data-v-9b797284>黑马头条</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98/%E9%BB%91%E9%A9%AC%E5%A4%B4%E6%9D%A1/%E5%9F%BA%E7%A1%80%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>基础篇</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98/%E9%BB%91%E9%A9%AC%E5%A4%B4%E6%9D%A1/%E8%BF%9B%E9%98%B6%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>进阶篇</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98/%E9%BB%91%E9%A9%AC%E5%A4%B4%E6%9D%A1/%E8%BF%9B%E9%98%B6%E7%AF%872.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>进阶篇2</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98/%E9%BB%91%E9%A9%AC%E5%A4%B4%E6%9D%A1/%E9%AB%98%E7%BA%A7%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>高级篇</p><!--]--></a><!----></div><!----></div><!--]--></div></section><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98/%E6%94%AF%E4%BB%98.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>支付</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98/%E9%A1%B9%E7%9B%AE%E6%8E%A8%E8%8D%90.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>项目推荐</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0" data-v-845b8fc6 data-v-9b797284><!----><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/team.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>团队成员</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><!--]--><!--[--><!--]--></nav></aside><div class="VPContent has-sidebar" id="VPContent" data-v-255ec12d data-v-669faec9><div class="VPDoc has-sidebar has-aside" data-v-669faec9 data-v-6b87e69f><!--[--><!--]--><div class="container" data-v-6b87e69f><div class="aside" data-v-6b87e69f><div class="aside-curtain" data-v-6b87e69f></div><div class="aside-container" data-v-6b87e69f><div class="aside-content" data-v-6b87e69f><div class="VPDocAside" data-v-6b87e69f data-v-3f215769><!--[--><!--]--><!--[--><!--]--><div class="VPDocAsideOutline" data-v-3f215769 data-v-ff0f39c8><div class="content" data-v-ff0f39c8><div class="outline-marker" data-v-ff0f39c8></div><div class="outline-title" data-v-ff0f39c8>On this page</div><nav aria-labelledby="doc-outline-aria-label" data-v-ff0f39c8><span class="visually-hidden" id="doc-outline-aria-label" data-v-ff0f39c8> Table of Contents for current page </span><ul class="root" data-v-ff0f39c8 data-v-d0ee3533><!--[--><!--]--></ul></nav></div></div><!--[--><!--]--><div class="spacer" data-v-3f215769></div><!--[--><!--]--><!----><!--[--><!--]--><!--[--><!--]--></div></div></div></div><div class="content" data-v-6b87e69f><div class="content-container" data-v-6b87e69f><!--[--><!--]--><!----><main class="main" data-v-6b87e69f><div style="position:relative;" class="vp-doc _notebook_%E4%B8%89%E9%AB%98_%E9%AB%98%E5%8F%AF%E7%94%A8" data-v-6b87e69f><div><h1 id="高可用⭐" tabindex="-1">高可用⭐ <a class="header-anchor" href="#高可用⭐" aria-label="Permalink to &quot;高可用⭐&quot;">​</a></h1><p>大型互联网架构设计，讲究一个<code>四件套</code>组合拳玩法，<code>高并发</code>、<code>高性能</code>、<code>高可用</code>、<code>高扩展</code>。</p><p>如果能掌握这四个方面，应付大厂面试以及日常工作中的架构方案设计基本不是什么难题。</p><p>今天，Tom哥就带大家学习下<code>高可用</code>都有哪些设计技巧？</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.30/202207072124817.png" alt="image-20220707212442710" style="zoom:50%;"><h2 id="一、系统拆分" tabindex="-1">一、系统拆分 <a class="header-anchor" href="#一、系统拆分" aria-label="Permalink to &quot;一、系统拆分&quot;">​</a></h2><p>有句古话 &quot;牵一发而动全身&quot;。</p><p>面对一个庞然大物，如果没有一个合理的分工分层。任何一个小小失误都会被无限放大，酿成巨大灾难。</p><p>万物相通，回到我们的软件架构。</p><p>早前的系统都是单体系统，比如电商业务，会员、商品、订单、物流、营销等模块都堆积在一个系统。每到节假日搞个大促活动，系统扩容时，一扩全扩，一挂全挂。只要一个接口出了问题，整个系统都不可用。</p><p>“鸡蛋不能放在一个篮子里”，这种连带风险换谁都承受不起。</p><p>因此，<code>系统拆分</code> 成了更多人的选择。</p><p>慢慢的就有了我们现在看到的<code>微服务</code>架构，将一个复杂的业务域按DDD的思想拆分成若干子系统，每个子系统负责专属的业务功能，做好垂直化建设，各个子系统之间做好边界隔离，降低风险蔓延。</p><h2 id="二、解耦" tabindex="-1">二、解耦 <a class="header-anchor" href="#二、解耦" aria-label="Permalink to &quot;二、解耦&quot;">​</a></h2><p>软件开发有个重要原则“高内聚、低耦合”。</p><p>小到<code>接口抽象</code>、<code>MVC 分层</code>，大到 <code>SOLID 原则</code>、<code>23种设计模式</code>。核心都是降低不同模块间的耦合度，避免一处错误改动影响到整个系统。</p><p>就以<code>开闭原则</code>为例，对扩展是开放的，对修改是关闭的。随着业务功能迭代，如何做到每次改动不对原来的旧代码产生影响。</p><p>Spring 框架给我们提供了一个很好的思路，里面有个重要设计 <code>AOP</code> ，全称（Aspect Oriented Programming），面向切面编程。</p><p>核心就是采用动态代理技术，通过对字节码进行增强，在方法调用的时候进行拦截，以便于在方法调用前后，增加我们需要的额外处理逻辑。</p><p>当然还有一个重要思路就是<code>事件机制</code>，通过<code>发布订阅模式</code>，新增的需求，只需要订阅对应的<code>事件通知</code>，针对性消费即可。不会对原来的代码侵入性修改，是不是会好很多。</p><h2 id="三、异步" tabindex="-1">三、异步 <a class="header-anchor" href="#三、异步" aria-label="Permalink to &quot;三、异步&quot;">​</a></h2><p>同步指一个进程在执行请求的时候，若该请求需要一段时间才能返回信息，那么这个进程将会一直等待下去，直到收到返回信息才继续执行下去。</p><p>效率会大大降低，聪明的人想到了 <code>异步</code> 方式。</p><p>如果是非实时响应的动作可以采用异步来完成，线程不需要一直等待，而是继续执行后面的逻辑。</p><p>如：线程池（ThreadPoolExecutor）、消息队列 等都是这个原理</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.30/202207072125887.png" alt="image-20220707212540810" style="zoom:67%;"><p>比如一个用户在淘宝下了一笔购物订单，关心的是订单是否创建成功，能否进行后续的付款流程</p><p>至于其他业务动作，如短信通知、邮件通知、生成订单快照、创建超时任务记录，这些非核心动作用户并不是特别关心。</p><p>我们可以采用消息队列的<code>发布/订阅</code> 机制，数据库插入订单记录后，发布一条消息到 MQ，然后就可以告知用户下单成功。</p><p>其他事情，由不同的 Task 任务订阅消息异步处理，彼此间互不干扰。</p><h2 id="四、重试" tabindex="-1">四、重试 <a class="header-anchor" href="#四、重试" aria-label="Permalink to &quot;四、重试&quot;">​</a></h2><p>重试主要是体现在远程的RPC调用，受 <code>网络抖动</code>、<code>线程资源阻塞</code> 等因素影响，请求无法及时响应。</p><p>为了提升用户体验，调用方可以通过 <code>重试</code> 方式再次发送请求，尝试获取结果。比过：浏览器的 F5 刷新机制就是类似道理。</p><p>接口重试是一把双刃剑，虽然客户端收到了<code>响应超时</code>结果，但是我们无法确定，服务端是否已经执行完成。如果盲目地重试，可能会带来严重后果。比如：银行转账。</p><p><code>重试</code>通常跟<code>幂等</code>组合使用，如果一个接口支持了 <code>幂等</code>，那你就可以随便重试</p><p>关于的 <code>幂等</code> 的解决方案</p><ul><li>插入前先执行查询操作，看是否存在，再决定是否插入</li><li>增加唯一索引</li><li>建防重表</li><li>引入状态机，比如付款后，订单状态调整为<code>已付款</code>，SQL 更新记录前 增加条件判断</li><li>增加分布式锁</li><li>采用 Token 机制，服务端增加 token 校验，只有第一次请求是合法的</li></ul><h2 id="五、补偿" tabindex="-1">五、补偿 <a class="header-anchor" href="#五、补偿" aria-label="Permalink to &quot;五、补偿&quot;">​</a></h2><p>我们知道不是所有的请求都能收到成功响应。除了上面的 <code>重试</code> 机制外，我们还可以采用补偿玩法，实现数据<code>最终一致性</code>。</p><p>业务补偿根据处理的方向分为两部分：</p><ul><li>正向。多个操作构成一个分布式事务，如果部分成功、部分失败，我们会通过最大努力机制将<code>失败</code>的任务推进到成功状态</li><li>逆向。同上道理，我们也可以采用反向操作，将部分成功任务恢复到<code>初始状态</code></li></ul><blockquote><p>注意：补偿操作有个重要前提，业务能接受短时间内的数据不一致。</p></blockquote><p>补偿有很多的实现方式：</p><p>1、本地建表方式，存储相关数据，然后通过定时任务扫描提取，并借助反射机制触发执行</p><p>2、也可以采用简单的消息中间件，构建业务消息体，由下游的的消费任务执行。如果失败，可以借助MQ的重试机制，多次重试</p><h2 id="六、备份" tabindex="-1">六、备份 <a class="header-anchor" href="#六、备份" aria-label="Permalink to &quot;六、备份&quot;">​</a></h2><p>任何服务器都有宕机的可能性，一旦存储了数据，带上状态，如果发生故障，数据丢失，后果是我们无法承受的。</p><p>所以，<code>容灾备份</code>也就变成了互联网的基本能力。</p><p>那如何备份，不同的框架有不用的玩法。我们以 Redis 为例：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.30/202207072127472.png" alt="image-20220707212747377" style="zoom:50%;"><p>Redis 借助 <code>RDB</code> 和 <code>AOF</code> 来实现两台服务器间的数据同步</p><ul><li>RDB，全量数据同步</li><li>AOF，增量数据同步，回放日志</li></ul><p>一旦主节点挂了怎么办？</p><p>这里引入哨兵机制。哨兵机制可以实现主从库的自动切换，有效解决了故障转移。整个过程分为三个阶段：监控、选主、通知。</p><p>除了 Redis 中间件外，其他常见的 MySQL、Kafka 消息中间件、HBase 、ES 等 ，凡是涉及到数据存储的介质，都有备份机制，一旦主节点挂了，会启用备份节点，保证数据不会丢失。</p><h2 id="七、多活策略" tabindex="-1">七、多活策略 <a class="header-anchor" href="#七、多活策略" aria-label="Permalink to &quot;七、多活策略&quot;">​</a></h2><p>虽然有了上面的<code>备份</code>策略，那是不是就万事大吉呢？</p><p>在一些极端情况，如：机房断电、机房火灾、地震、山洪等不可抗力因素，所有的服务器都可能出现故障，无法对外提供服务，导致整体业务瘫痪。</p><p>为了降低风险，保证服务的24小时可用性，我们会采用 <code>多活策略</code>。</p><p>常见的<code>多活</code>方案有，<code>同城双活</code>、<code>两地三中心</code>、<code>三地五中心</code>、<code>异地双活</code>、<code>异地多活</code></p><p>不同的方案技术要求、建设成本、运维成本也都不一样。</p><p>多活的技术方案复杂，需要考虑的问题点也非常多，这里只是抛砖引玉就不过多展开</p><h2 id="八、隔离" tabindex="-1">八、隔离 <a class="header-anchor" href="#八、隔离" aria-label="Permalink to &quot;八、隔离&quot;">​</a></h2><p>隔离属于物理层面的分割，将若干的系统低耦合设计，独立部署，从物理上隔开。</p><p>每个子系统有自己独立的代码库，独立开发，独立发布。一旦出现故障，也不会相互干扰。当然如果不同子系统间有相互依赖，这种情况比较特殊，需要有默认值或者异常特殊处理，这属于业务层面解决方案。</p><p>隔离属于分布式技术的衍生产物，我们最常见的微服务解决方案。</p><p>将一个大型的复杂系统拆分成若干个微服务系统，这些微服务子系统通常由不同的团队开发、维护，独立部署，服务之间通过 <code>RPC</code> 远程调用。</p><p>隔离使得系统间边界更加清晰，故障可以更加隔离开来，问题的发现与解决也更加快速，系统的可用性也更高。</p><h2 id="九、限流" tabindex="-1">九、限流 <a class="header-anchor" href="#九、限流" aria-label="Permalink to &quot;九、限流&quot;">​</a></h2><p>高并发系统，如果遇到流量洪峰，超过了当前系统的承载能力。我们要怎么办？</p><p>一种方案，照单全收，CPU、内存、Load负载飚的很高，最后处理不过来，所有请求都超时无法正常响应。</p><p>另一种解决方案，“舍得，有舍有得”，多余的流量我们直接丢弃。</p><p>限流定义：</p><blockquote><p>限制到达系统的并发请求数量，保证系统能够正常响应部分用户请求，而对于超过限制的流量，则通过拒绝服务的方式保证整体系统的可用性。</p></blockquote><p><strong>根据作用范围：限流分为单机版限流、分布式限流</strong></p><p>1、单机版限流</p><p>主要借助于本机内存来实现计数器，比如通过AtomicLong#incrementAndGet()，但是要注意之前不用的key定期做清理，释放内存。</p><p>纯内存实现，无需和其他节点统计汇总，性能最高。但是优点也是缺点，无法做到全局统一化的限流。</p><p>2、分布式限流</p><p>单机版限流仅能保护自身节点，但无法保护应用依赖的各种服务，并且在进行节点扩容、缩容时也无法准确控制整个服务的请求限制。而分布式限流，以集群为维度，可以方便的控制这个集群的请求限制，从而保护下游依赖的各种服务资源。</p><p><strong>限流支持多个维度：</strong></p><ul><li>整个系统一定时间内（比如每分钟）处理多少请求</li><li>单个接口一定时间内处理多少流量</li><li>单个IP、城市、渠道、设备id、用户id等在一定时间内发送的请求数</li><li>如果是开放平台，则为每个appkey设置独立的访问速率规则</li></ul><p><strong>常见的限流算法：</strong></p><ul><li>计数器限流</li><li>滑动窗口限流</li><li>漏桶限流</li><li>令牌桶限流</li></ul><h2 id="十、熔断" tabindex="-1">十、熔断 <a class="header-anchor" href="#十、熔断" aria-label="Permalink to &quot;十、熔断&quot;">​</a></h2><p>关键字：<code>断路保护</code>。比如 A 服务调用 B 服务，由于网络问题或 B 服务宕机了或 B 服务的处理时间长，导致请求的时间超长，如果在一定时间内多次出现这种情况，就可以直接将 B 断路了（A 不再请求B）。而调用 B 服务的请求直接返回降级数据，不必等待 B 服务的执行。因此 B 服务的问题，不会级联影响到 A 服务。</p><p>熔断，其实是对调用链路中某个资源出现不稳定状态时（如：调用超时或异常比例升高），对这个资源的调用进行限制，让请求快速失败，避免影响到其它的资源而导致级联错误。</p><p>熔断的主要方式是使用断路器阻断对故障服务器的调用</p><p>断路器有三种状态，关闭、打开、半打开。</p><p><strong>状态机：</strong></p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.30/202207072129080.png" alt="image-20220707212916989" style="zoom:67%;"><p>1、关闭（Closed）状态：在这个状态下，请求都会被转发给后端服务。同时会记录请求失败的次数，当请求失败次数在一段时间超过一定次数就会进入打开状态。</p><p>2、打开（Open）状态：在这个状态下，熔断器会直接拒绝请求，返回错误，而不去调用后端服务。同时，会有一个定时器，时间到的时候会变成半打开状态。目的是假设服务会在一段时间内恢复正常。</p><p>3、半打开（Half Open）状态：在这个状态下，熔断器会尝试把部分请求转发给后端服务，目的是为了探测后端服务是否恢复。如果请求失败会进入打开状态，成功情况下会进入关闭状态，同时重置计数。</p><p>目前，市面流行的解决方案是阿里的开源框架 <code>Sentinel</code>，提供了Dashboard控制台用于定义资源以及规则配置</p><h2 id="十一、降级" tabindex="-1">十一、降级 <a class="header-anchor" href="#十一、降级" aria-label="Permalink to &quot;十一、降级&quot;">​</a></h2><p>降级是系统保护的一种重要手段。</p><p>正如 “好钢用在刀刃上”，为了使<code>有限资源</code>发挥最大价值，我们会临时关闭一些非核心功能，减轻系统压力，并将有限资源留给核心业务。</p><p>比如电商大促，业务在峰值时刻，系统抵挡不住全部的流量时，系统的负载、CPU 的使用率都超过了预警水位，可以对一些非核心的功能进行降级，降低系统压力，比如把<code>商品评价</code>、<code>成交记录</code>等功能临时关掉。弃车保帅，保证 <code>创建订单</code>、<code>订单支付</code> 等核心功能的正常使用。</p><p>当然，不同业务、不同公司，处理方式也各不相同，需要结合实际场景，和业务方同学一块讨论，最后达成一个统一认可的降级方案。</p><p>降级数据可以简单理解为快速返回了一个 false，前端页面告诉用户“服务器当前正忙，请稍后再试。”</p><p><strong>总结下来：降级是通过暂时关闭某些非核心服务或者组件从而保护核心系统的可用性。</strong></p><p><strong>熔断和降级的相同点？</strong></p><ul><li>熔断和限流都是为了保证集群大部分服务的可用性和可靠性。防止核心服务崩溃</li><li>给终端用户的感受就是某个功能不可用。</li></ul><p><strong>熔断和降级的不同点？</strong></p><ul><li><p>熔断是被调用方出现了故障，主动触发的操作。</p></li><li><p>降级是基于全局考虑，停止某些正常服务，释放资源。</p></li><li></li></ul><h1 id="异地多活策略⭐" tabindex="-1">异地多活策略⭐ <a class="header-anchor" href="#异地多活策略⭐" aria-label="Permalink to &quot;异地多活策略⭐&quot;">​</a></h1><p><a href="https://mp.weixin.qq.com/s?__biz=MzkwNjMwMTgzMQ==&amp;mid=2247490455&amp;idx=1&amp;sn=74013dfc33c7d46626dca1a7ae048419&amp;chksm=c0ebc37ff79c4a699b15040002f35ee7993dcf002cde34c2599234110369ea4f4732854c5f75&amp;mpshare=1&amp;scene=23&amp;srcid=0707hWPH2XI0K8OPVhubL1o6&amp;sharer_sharetime=1657153405654&amp;sharer_shareid=29b8a04db1dbd975e3bf4e9f47e7ac67#rd" target="_blank" rel="noreferrer">搞懂异地多活，看这篇就够了 (qq.com)</a></p><p>在软件开发领域，「异地多活」是分布式系统架构设计的一座高峰，很多人经常听过它，但很少人理解其中的原理。</p><p><strong>异地多活到底是什么？为什么需要异地多活？它到底解决了什么问题？究竟是怎么解决的？</strong></p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.30/202207072133478.png" alt="image-20220707213351421" style="zoom:50%;"><h2 id="_01-系统可用性⭐" tabindex="-1">01 系统可用性⭐ <a class="header-anchor" href="#_01-系统可用性⭐" aria-label="Permalink to &quot;01 系统可用性⭐&quot;">​</a></h2><p>要想理解异地多活，我们需要从架构设计的原则说起。</p><p>现如今，我们开发一个软件系统，对其要求越来越高，如果你了解一些「架构设计」的要求，就知道一个好的软件架构应该遵循以下 3 个原则：</p><ol><li>高性能</li><li>高可用</li><li>易扩展</li></ol><p>其中，高性能意味着系统拥有更大流量的处理能力，更低的响应延迟。例如 1 秒可处理 10W 并发请求，接口响应时间 5 ms 等等。</p><p>易扩展表示系统在迭代新功能时，能以最小的代价去扩展，系统遇到流量压力时，可以在不改动代码的前提下，去扩容系统。</p><p>而「高可用」这个概念，看起来很抽象，怎么理解它呢？通常用 2 个指标来衡量：</p><ul><li><strong>平均故障间隔 MTBF</strong>（Mean Time Between Failure）：表示两次故障的间隔时间，也就是系统「正常运行」的平均时间，这个时间越长，说明系统稳定性越高</li><li><strong>故障恢复时间 MTTR</strong>（Mean Time To Repair）：表示系统发生故障后「恢复的时间」，这个值越小，故障对用户的影响越小</li></ul><p>可用性与这两者的关系：</p><blockquote><p>可用性（Availability）= MTBF / (MTBF + MTTR) * 100%</p></blockquote><h3 id="n个9分析⭐" tabindex="-1">N个9分析⭐ <a class="header-anchor" href="#n个9分析⭐" aria-label="Permalink to &quot;N个9分析⭐&quot;">​</a></h3><p>这个公式得出的结果是一个「比例」，通常我们会用「N 个 9」来描述一个系统的可用性。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.30/202207072134403.png" alt="image-20220707213432340" style="zoom:67%;"><p>从这张图你可以看到，要想达到 4 个 9 以上的可用性，平均每天故障时间必须控制在 10 秒以内。</p><p>来反观下 B 站故障了多久，2021-07-13 23:00 到 2021-07-14 02:00，系统逐渐恢复，如果按照年故障总时间来算的话：B 站故障超过 1 个小时了，只能算达到了三个九的标准。如果按照日故障时间来算，只能达到两个九的标准，也就是 99% 的高可用性，有点惨...</p><p><strong>1 一个九和两个九</strong></p><p>非常容易达到，一个正常的线上系统不会每天宕机 15 分钟吧，不然真用不下去了。</p><p><strong>2 三个九和四个九</strong></p><p>允许故障的时间很短，年故障时间是 1 小时到 8 小时，需要从架构设计、代码质量、运维体系、故障处理手册等入手，其中非常关键的一环是运维体系，如果线上出了问题，第一波收到异常通知的肯定是运维团队，根据问题的严重程度，会有不同的运维人员来处理，像 B 站这种大事故，就得运维负责人亲自上阵了。</p><p>另外在紧急故障发生时，是否可以人工手段降级或者加开关，限制部分功能，也是需要考虑的。之前我遇到过一个问题，二维码刷卡功能出现故障，辛亏之前做了一个开关，可以将二维码功能隐藏，如果用户要使用二维码刷卡功能，统一引导用户走线下刷卡功能。</p><p><strong>3 五个九</strong></p><p>年故障时间 5 分钟以内，这个相当短，即使有强大的运维团队每天值班也很难在收到异常报警后，5 分钟内快速恢复，所以只能用自动化运维来解决。也就是服务器自己来保证系统的容灾和自动恢复的能力。</p><p><strong>4 六个九</strong></p><p>这个标准相当苛刻了，年故障时间 32 秒。</p><p>针对不同的系统，其实对几个九也不相同。比如公司内部的员工系统，要求四个九就可以，如果是给全国用户使用，且使用人数很多，比如某宝、某饿，那么就要求五个九以上了，但是即使是数一数二的电商系统，它里面也有非核心的业务，其实也可以放宽限制，四个九足以，这个就看各家系统的要求，都是成本、人力、重要程度的权衡考虑。</p><p>也就是说，只有故障的时间「越短」，整个系统的可用性才会越高，每提升 1 个 9，都会对系统提出更高的要求。</p><h3 id="故障体现方面" tabindex="-1">故障体现方面 <a class="header-anchor" href="#故障体现方面" aria-label="Permalink to &quot;故障体现方面&quot;">​</a></h3><p>我们都知道，系统发生故障其实是不可避免的，尤其是规模越大的系统，发生问题的概率也越大。这些故障一般体现在 3 个方面：</p><ol><li><strong>硬件故障</strong>：CPU、内存、磁盘、网卡、交换机、路由器</li><li><strong>软件问题</strong>：代码 Bug、版本迭代</li><li><strong>不可抗力</strong>：地震、水灾、火灾、战争</li></ol><p>这些风险随时都有可能发生。所以，在面对故障时，我们的系统能否以「<strong>最快</strong>」的速度恢复，就成为了可用性的关键。</p><p>可如何做到快速恢复呢？</p><p>这篇文章要讲的「异地多活」架构，就是为了解决这个问题，而提出的高效解决方案。</p><p>下面，我会从一个最简单的系统出发，带你一步步演化出一个支持「异地多活」的系统架构。</p><p>在这个过程中，你会看到一个系统会遇到哪些可用性问题，以及为什么架构要这样演进，从而理解异地多活架构的意义。</p><h2 id="_02-单机架构" tabindex="-1">02 单机架构 <a class="header-anchor" href="#_02-单机架构" aria-label="Permalink to &quot;02 单机架构&quot;">​</a></h2><p>我们从最简单的开始讲起。</p><p>假设你的业务处于起步阶段，体量非常小，那你的架构是这样的：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.30/202207072134891.png" alt="image-20220707213457842" style="zoom:50%;"><p>这个架构模型非常简单，客户端请求进来，业务应用读写数据库，返回结果，非常好理解。</p><p>但需要注意的是，这里的数据库是「单机」部署的，所以它有一个致命的缺点：一旦遭遇意外，例如磁盘损坏、操作系统异常、误删数据，那这意味着所有数据就全部「丢失」了，这个损失是巨大的。</p><p>如何避免这个问题呢？我们很容易想到一个方案：<strong>备份</strong>。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.30/202207072135212.png" alt="image-20220707213516129" style="zoom:50%;"><p>你可以对数据做备份，把数据库文件「定期」cp 到另一台机器上，这样，即使原机器丢失数据，你依旧可以通过备份把数据「恢复」回来，以此保证数据安全。</p><p>这个方案实施起来虽然比较简单，但存在 2 个问题：</p><ol><li><strong>恢复需要时间</strong>：业务需先停机，再恢复数据，停机时间取决于恢复的速度，恢复期间服务「不可用」</li><li><strong>数据不完整</strong>：因为是定期备份，数据肯定不是「最新」的，数据完整程度取决于备份的周期</li></ol><p>很明显，你的数据库越大，意味故障恢复时间越久。那按照前面我们提到的「高可用」标准，这个方案可能连 1 个 9 都达不到，远远无法满足我们对可用性的要求。</p><p>那有什么更好的方案，既可以快速恢复业务？还能尽可能保证数据完整性呢？</p><p>这时你可以采用这个方案：<strong>主从副本</strong>。</p><h2 id="_03-主从副本" tabindex="-1">03 主从副本 <a class="header-anchor" href="#_03-主从副本" aria-label="Permalink to &quot;03 主从副本&quot;">​</a></h2><p>你可以在另一台机器上，再部署一个数据库实例，让这个新实例成为原实例的「副本」，让两者保持「实时同步」，就像这样：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.30/202207072136257.png" alt="image-20220707213613177" style="zoom:50%;"><p>我们一般把原实例叫作主库（master），新实例叫作从库（slave）。这个方案的优点在于：</p><ul><li><strong>数据完整性高</strong>：主从副本实时同步，数据「差异」很小</li><li><strong>抗故障能力提升</strong>：主库有任何异常，从库可随时「切换」为主库，继续提供服务</li><li><strong>读性能提升</strong>：业务应用可直接读从库，分担主库「压力」读压力</li></ul><p>这个方案不错，不仅大大提高了数据库的可用性，还提升了系统的读性能。</p><p>同样的思路，你的「业务应用」也可以在其它机器部署一份，避免单点。因为业务应用通常是「无状态」的（不像数据库那样存储数据），所以直接部署即可，非常简单。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.30/202207072140054.png" alt="image-20220707214041974" style="zoom:50%;"><p>因为业务应用部署了多个，所以你现在还需要部署一个「接入层」，来做请求的「负载均衡」（一般会使用 nginx 或 LVS），这样当一台机器宕机后，另一台机器也可以「接管」所有流量，持续提供服务。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.30/202207072141729.png" alt="image-20220707214101633" style="zoom:50%;"><p>从这个方案你可以看出，提升可用性的关键思路就是：<strong>冗余</strong>。</p><p>没错，担心一个实例故障，那就部署多个实例，担心一个机器宕机，那就部署多台机器。</p><p>到这里，你的架构基本已演变成主流方案了，之后开发新的业务应用，都可以按照这种模式去部署。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.30/202207072141867.png" alt="image-20220707214135743" style="zoom:50%;"><p>但这种方案还有什么风险吗？</p><h2 id="_04-风险不可控" tabindex="-1">04 风险不可控 <a class="header-anchor" href="#_04-风险不可控" aria-label="Permalink to &quot;04 风险不可控&quot;">​</a></h2><p>现在让我们把视角下放，把焦点放到具体的「部署细节」上来。</p><p>按照前面的分析，为了避免单点故障，你的应用虽然部署了多台机器，但这些机器的分布情况，我们并没有去深究。</p><p>而一个机房有很多服务器，这些服务器通常会分布在一个个「机柜」上，如果你使用的这些机器，刚好在一个机柜，还是存在风险。</p><p>如果恰好连接这个机柜的交换机 / 路由器发生故障，那么你的应用依旧有「不可用」的风险。</p><blockquote><p>虽然交换机 / 路由器也做了路线冗余，但不能保证一定不出问题。</p></blockquote><p>部署在一个机柜有风险，那把这些机器打散，分散到不同机柜上，是不是就没问题了？</p><p>这样确实会大大降低出问题的概率。但我们依旧不能掉以轻心，因为无论怎么分散，它们总归还是在一个相同的环境下：<strong>机房</strong>。</p><p>那继续追问，机房会不会发生故障呢？</p><p>一般来讲，建设一个机房的要求其实是很高的，地理位置、温湿度控制、备用电源等等，机房厂商会在各方面做好防护。但即使这样，我们每隔一段时间还会看到这样的新闻：</p><ul><li>2015 年 5 月 27 日，杭州市某地光纤被挖断，近 3 亿用户长达 5 小时无法访问支付宝</li><li>2021 年 7 月 13 日，B 站部分服务器机房发生故障，造成整站持续 3 个小时无法访问</li><li>2021 年 10 月 9 日，富途证券服务器机房发生电力闪断故障，造成用户 2 个小时无法登陆、交易</li><li>...</li></ul><p>可见，即使机房级别的防护已经做得足够好，但只要有「概率」出问题，那现实情况就有可能发生。虽然概率很小，但一旦真的发生，影响之大可见一斑。</p><p>看到这里你可能会想，机房出现问题的概率也太小了吧，工作了这么多年，也没让我碰上一次，有必要考虑得这么复杂吗？</p><p>但你有没有思考这样一个问题：<strong>不同体量的系统，它们各自关注的重点是什么？</strong></p><p>体量很小的系统，它会重点关注「用户」规模、增长，这个阶段获取用户是一切。等用户体量上来了，这个阶段会重点关注「性能」，优化接口响应时间、页面打开速度等等，这个阶段更多是关注用户体验。</p><p>等体量再大到一定规模后你会发现，「可用性」就变得尤为重要。像微信、支付宝这种全民级的应用，如果机房发生一次故障，那整个影响范围可以说是非常巨大的。</p><p>所以，再小概率的风险，我们在提高系统可用性时，也不能忽视。</p><p>分析了风险，再说回我们的架构。那到底该怎么应对机房级别的故障呢？</p><p>没错，还是<strong>冗余</strong>。</p><h2 id="_05-同城灾备" tabindex="-1">05 同城灾备 <a class="header-anchor" href="#_05-同城灾备" aria-label="Permalink to &quot;05 同城灾备&quot;">​</a></h2><p>想要抵御「机房」级别的风险，那应对方案就不能局限在一个机房内了。</p><p>现在，你需要做机房级别的冗余方案，也就是说，你需要再搭建一个机房，来部署你的服务。</p><p>简单起见，你可以在「同一个城市」再搭建一个机房，原机房我们叫作 A 机房，新机房叫 B 机房，这两个机房的网络用一条「专线」连通。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.30/202207072142188.png" alt="image-20220707214258065" style="zoom:50%;"><p>有了新机房，怎么把它用起来呢？这里还是要优先考虑「数据」风险。</p><p>为了避免 A 机房故障导致数据丢失，所以我们需要把数据在 B 机房也存一份。最简单的方案还是和前面提到的一样：<strong>备份</strong>。</p><p>A 机房的数据，定时在 B 机房做备份（拷贝数据文件），这样即使整个 A 机房遭到严重的损坏，B 机房的数据不会丢，通过备份可以把数据「恢复」回来，重启服务。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.30/202207072143942.png" alt="image-20220707214329825" style="zoom:50%;"><p>这种方案，我们称之为「<strong>冷备</strong>」。为什么叫冷备呢？因为 B 机房只做备份，不提供实时服务，它是冷的，只会在 A 机房故障时才会启用。</p><p>但备份的问题依旧和之前描述的一样：数据不完整、恢复数据期间业务不可用，整个系统的可用性还是无法得到保证。</p><p>所以，我们还是需要用「主从副本」的方式，在 B 机房部署 A 机房的数据副本，架构就变成了这样：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.30/202207072144251.png" alt="image-20220707214443131" style="zoom:50%;"><p>这样，就算整个 A 机房挂掉，我们在 B 机房也有比较「完整」的数据。</p><p>数据是保住了，但这时你需要考虑另外一个问题：<strong>如果 A 机房真挂掉了，要想保证服务不中断，你还需要在 B 机房「紧急」做这些事情</strong>：</p><ol><li>B 机房所有从库提升为主库</li><li>在 B 机房部署应用，启动服务</li><li>部署接入层，配置转发规则</li><li>DNS 指向 B 机房，接入流量，业务恢复</li></ol><p>看到了么？A 机房故障后，B 机房需要做这么多工作，你的业务才能完全「恢复」过来。</p><p>你看，整个过程需要人为介入，且需花费大量时间来操作，恢复之前整个服务还是不可用的，这个方案还是不太爽，如果能做到故障后立即「切换」，那就好了。</p><p>因此，要想缩短业务恢复的时间，你必须把这些工作在 B 机房「<strong>提前</strong>」做好，也就是说，你需要在 B 机房提前部署好接入层、业务应用，等待随时切换。架构就变成了这样：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.30/202207072145478.png" alt="image-20220707214511338" style="zoom:50%;"><p>这样的话，A 机房整个挂掉，我们只需要做 2 件事即可：</p><ol><li>B 机房所有从库提升为主库</li><li>DNS 指向 B 机房，接入流量，业务恢复</li></ol><p>这样一来，恢复速度快了很多。</p><p>到这里你会发现，B 机房从最开始的「空空如也」，演变到现在，几乎是「<strong>镜像</strong>」了一份 A 机房的所有东西，从最上层的接入层，到中间的业务应用，到最下层的存储。</p><p>两个机房唯一的区别是，<strong>A 机房的存储都是主库，而 B 机房都是从库</strong>。</p><p>这种方案，我们把它叫做「<strong>热备</strong>」。</p><p>热的意思是指，B 机房处于「待命」状态，A 故障后 B 可以随时「接管」流量，继续提供服务。热备相比于冷备最大的优点是：<strong>随时可切换</strong>。</p><p>无论是冷备还是热备，因为它们都处于「备用」状态，所以我们把这两个方案统称为：<strong>同城灾备</strong>。</p><p>同城灾备的最大优势在于，我们再也不用担心「机房」级别的故障了，一个机房发生风险，我们只需把流量切换到另一个机房即可，可用性再次提高，是不是很爽？（后面还有更爽的）</p><h2 id="_06-同城双活" tabindex="-1">06 同城双活 <a class="header-anchor" href="#_06-同城双活" aria-label="Permalink to &quot;06 同城双活&quot;">​</a></h2><p>高性能的同城双活，核心思想就是避免跨机房调用：</p><p>保证同机房服务调用：不同的 PRC（远程调用） 服务，向注册中心注册不同的服务组，而 RPC 服务只订阅同机房的 RPC 服务组，RPC 调用只存在于本机房。</p><p>保证同机房缓存调用：查询缓存发生在本机房，如果没有，则从数据库加载。缓存也是采用主备的方式，数据更新采用多机房更新的方式。</p><p>保证同机房数据库查询：和缓存一样，读取本机房的数据库，同样采用主备方式。</p><p>我们继续来看这个架构。</p><p>虽然我们有了应对机房故障的解决方案，但这里有个问题是我们不能忽视的：<strong>A 机房挂掉，全部流量切到 B 机房，B 机房能否真的如我们所愿，正常提供服务？</strong></p><p>这是个值得思考的问题。</p><p>这就好比有两支军队 A 和 B，A 军队历经沙场，作战经验丰富，而 B 军队只是后备军，除了有军人的基本素养之外，并没有实战经验，战斗经验基本为 0。</p><p>如果 A 军队丧失战斗能力，需要 B 军队立即顶上时，作为指挥官的你，肯定也会担心 B 军队能否真的担此重任吧？</p><p>我们的架构也是如此，此时的 B 机房虽然是随时「待命」状态，但 A 机房真的发生故障，我们要把全部流量切到 B 机房，其实是不敢百分百保证它可以「如期」工作的。</p><p>你想，我们在一个机房内部署服务，还总是发生各种各样的问题，例如：发布应用的版本不一致、系统资源不足、操作系统参数不一样等等。现在多部署一个机房，这些问题只会增多，不会减少。</p><p>另外，从「成本」的角度来看，我们新部署一个机房，需要购买服务器、内存、硬盘、带宽资源，花费成本也是非常高昂的，只让它当一个后备军，未免也太「大材小用」了！</p><p>因此，我们需要让 B 机房也接入流量，实时提供服务，这样做的好处，<strong>一是可以实时训练这支后备军，让它达到与 A 机房相同的作战水平，随时可切换，二是 B 机房接入流量后，可以分担 A 机房的流量压力</strong>。这才是把 B 机房资源优势，发挥最大化的最好方案！</p><p>那怎么让 B 机房也接入流量呢？很简单，就是把 B 机房的接入层 IP 地址，加入到 DNS 中，这样，B 机房从上层就可以有流量进来了。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.30/202207072146457.png" alt="image-20220707214612352" style="zoom:50%;"><p>但这里有一个问题：别忘了，B 机房的存储，现在可都是 A 机房的「从库」，从库默认可都是「不可写」的，B 机房的写请求打到本机房存储上，肯定会报错，这还是不符合我们预期。怎么办？</p><p>这时，你就需要在「业务应用」层做改造了。</p><p>你的业务应用在操作数据库时，需要区分「<strong>读写分离</strong>」（一般用中间件实现），即两个机房的「读」流量，可以读任意机房的存储，但「写」流量，只允许写 A 机房，因为主库在 A 机房。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.30/202207072146747.png" alt="image-20220707214637650" style="zoom:50%;"><p>这会涉及到你用的所有存储，例如项目中用到了 MySQL、Redis、MongoDB 等等，操作这些数据库，都需要区分读写请求，所以这块需要一定的业务「改造」成本。</p><p>因为 A 机房的存储都是主库，所以我们把 A 机房叫做「<strong>主机房</strong>」，B 机房叫「<strong>从机房</strong>」。</p><p>两个机房部署在「同城」，物理距离比较近，而且两个机房用「专线」网络连接，虽然跨机房访问的延迟，比单个机房内要大一些，但整体的延迟还是可以接受的。</p><p>业务改造完成后，B 机房可以慢慢接入流量，从 10%、30%、50% 逐渐覆盖到 100%，你可以持续观察 B 机房的业务是否存在问题，有问题及时修复，逐渐让 B 机房的工作能力，达到和 A 机房相同水平。</p><p>现在，因为 B 机房实时接入了流量，此时如果 A 机房挂了，那我们就可以「大胆」地把 A 的流量，全部切换到 B 机房，完成快速切换！</p><p>到这里你可以看到，我们部署的 B 机房，在物理上虽然与 A 有一定距离，但整个系统从「逻辑」上来看，我们是把这两个机房看做一个「整体」来规划的，也就是说，相当于把 2 个机房当作 1 个机房来用。</p><p>这种架构方案，比前面的同城灾备更「进了一步」，B 机房实时接入了流量，还能应对随时的故障切换，这种方案我们把它叫做「<strong>同城双活</strong>」。</p><p>因为两个机房都能处理业务请求，这对我们系统的内部维护、改造、升级提供了更多的可实施空间（流量随时切换），现在，整个系统的弹性也变大了，是不是更爽了？</p><p>那这种架构有什么问题呢？</p><h2 id="_07-两地三中心" tabindex="-1">07 两地三中心 <a class="header-anchor" href="#_07-两地三中心" aria-label="Permalink to &quot;07 两地三中心&quot;">​</a></h2><p>这个概念也被业界提到过很多次。</p><p>两地：本地和异地。</p><p>三中心：本地数据中心、同城数据中心、异地数据中心。</p><p>这两个概念也就是我上面说的同城双活和异地多活的方式，只是针对的是数据中心。原理如下图所示：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202208221020946.png" alt="image-20220822102000880" style="zoom:67%;"><p>还是回到风险上来说。</p><p>虽然我们把 2 个机房当做一个整体来规划，但这 2 个机房在物理层面上，还是处于「一个城市」内，如果是整个城市发生自然灾害，例如地震、水灾（河南水灾刚过去不久），那 2 个机房依旧存在「全局覆没」的风险。</p><p>真是防不胜防啊？怎么办？没办法，继续冗余。</p><p>但这次冗余机房，就不能部署在同一个城市了，你需要把它放到距离更远的地方，部署在「异地」。</p><blockquote><p>通常建议两个机房的距离要在 1000 公里以上，这样才能应对城市级别的灾难。</p></blockquote><p>假设之前的 A、B 机房在北京，那这次新部署的 C 机房可以放在上海。</p><p>按照前面的思路，把 C 机房用起来，最简单粗暴的方案还就是做「冷备」，即定时把 A、B 机房的数据，在 C 机房做备份，防止数据丢失。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.30/202207072147564.png" alt="image-20220707214731436" style="zoom:50%;"><p>这种方案，就是我们经常听到的「<strong>两地三中心</strong>」。</p><p><strong>两地是指 2 个城市，三中心是指有 3 个机房，其中 2 个机房在同一个城市，并且同时提供服务，第 3 个机房部署在异地，只做数据灾备。</strong></p><p>这种架构方案，通常用在银行、金融、政企相关的项目中。它的问题还是前面所说的，启用灾备机房需要时间，而且启用后的服务，不确定能否如期工作。</p><p>所以，要想真正的抵御城市级别的故障，越来越多的互联网公司，开始实施「<strong>异地双活</strong>」。</p><h2 id="_08-伪异地双活" tabindex="-1">08 伪异地双活 <a class="header-anchor" href="#_08-伪异地双活" aria-label="Permalink to &quot;08 伪异地双活&quot;">​</a></h2><p>这里，我们还是分析 2 个机房的架构情况。我们不再把 A、B 机房部署在同一个城市，而是分开部署，例如 A 机房放在北京，B 机房放在上海。</p><p>前面我们讲了同城双活，那异地双活是不是直接「照搬」同城双活的模式去部署就可以了呢？</p><p>事情没你想的那么简单。</p><p>如果还是按照同城双活的架构来部署，那异地双活的架构就是这样的：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.30/202207072148068.png" alt="image-20220707214827956" style="zoom:50%;"><p>注意看，两个机房的网络是通过「<strong>跨城专线</strong>」连通的。</p><p>此时两个机房都接入流量，那上海机房的请求，可能要去读写北京机房的存储，这里存在一个很大的问题：<strong>网络延迟</strong>。</p><p>因为两个机房距离较远，受到物理距离的限制，现在，两地之间的网络延迟就变成了「<strong>不可忽视</strong>」的因素了。</p><p>北京到上海的距离大约 1300 公里，即使架设一条高速的「网络专线」，光纤以光速传输，一个来回也需要近 10ms 的延迟。</p><p>况且，网络线路之间还会经历各种路由器、交换机等网络设备，实际延迟可能会达到 30ms ~ 100ms，如果网络发生抖动，延迟甚至会达到 1 秒。</p><blockquote><p>不止是延迟，远距离的网络专线质量，是远远达不到机房内网络质量的，专线网络经常会发生延迟、丢包、甚至中断的情况。总之，不能过度信任和依赖「跨城专线」。</p></blockquote><p>你可能会问，这点延迟对业务影响很大吗？影响非常大！</p><p>试想，一个客户端请求打到上海机房，上海机房要去读写北京机房的存储，一次跨机房访问延迟就达到了 30ms，这大致是机房内网网络（0.5 ms）访问速度的 60 倍（30ms / 0.5ms），一次请求慢 60 倍，来回往返就要慢 100 倍以上。</p><p>而我们在 App 打开一个页面，可能会访问后端几十个 API，每次都跨机房访问，整个页面的响应延迟有可能就达到了<strong>秒级</strong>，这个性能简直惨不忍睹，难以接受。</p><p>看到了么，虽然我们只是简单的把机房部署在了「异地」，但「同城双活」的架构模型，在这里就不适用了，还是按照这种方式部署，这是「伪异地双活」！</p><p>那如何做到真正的异地双活呢？</p><h2 id="_09-真正的异地双活" tabindex="-1">09 真正的异地双活 <a class="header-anchor" href="#_09-真正的异地双活" aria-label="Permalink to &quot;09 真正的异地双活&quot;">​</a></h2><p>既然「跨机房」调用延迟是不容忽视的因素，那我们只能尽量避免跨机房「调用」，规避这个延迟问题。</p><p>也就是说，上海机房的应用，不能再「跨机房」去读写北京机房的存储，只允许读写上海本地的存储，实现「就近访问」，这样才能避免延迟问题。</p><p>还是之前提到的问题：上海机房存储都是从库，不允许写入啊，除非我们只允许上海机房接入「读流量」，不接收「写流量」，否则无法满足不再跨机房的要求。</p><p>很显然，只让上海机房接收读流量的方案不现实，因为很少有项目是只有读流量，没有写流量的。所以这种方案还是不行，这怎么办？</p><p>此时，你就必须在「<strong>存储层</strong>」做改造了。</p><p>要想上海机房读写本机房的存储，那上海机房的存储不能再是北京机房的从库，而是也要变为「主库」。</p><p>你没看错，两个机房的存储必须都是「<strong>主库</strong>」，而且两个机房的数据还要「<strong>互相同步</strong>」数据，即客户端无论写哪一个机房，都能把这条数据同步到另一个机房。</p><p>因为只有两个机房都拥有「全量数据」，才能支持任意切换机房，持续提供服务。</p><p>怎么实现这种「双主」架构呢？它们之间如何互相同步数据？</p><p>如果你对 MySQL 有所了解，MySQL 本身就提供了双主架构，它支持双向复制数据，但平时用的并不多。而且 Redis、MongoDB 等数据库并没有提供这个功能，所以，你必须开发对应的「<strong>数据同步中间件</strong>」来实现双向同步的功能。</p><p>此外，除了数据库这种有状态的软件之外，你的项目通常还会使用到消息队列，例如 RabbitMQ、Kafka，这些也是有状态的服务，所以它们也需要开发双向同步的中间件，支持任意机房写入数据，同步至另一个机房。</p><p>看到了么，这一下子复杂度就上来了，单单针对每个数据库、队列开发同步中间件，就需要投入很大精力了。</p><blockquote><p>业界也开源出了很多数据同步中间件，例如阿里的 Canal、RedisShake、MongoShake，可分别在两个机房同步 MySQL、Redis、MongoDB 数据。</p><p>很多有能力的公司，也会采用自研同步中间件的方式来做，例如饿了么、携程、美团都开发了自己的同步中间件。</p><p>我也有幸参与设计开发了 MySQL、Redis/Codis、MongoDB 的同步中间件，有时间写一篇文章详细聊聊实现细节，欢迎持续关注。😃</p></blockquote><p>现在，整个架构就变成了这样：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.30/202207072153586.png" alt="image-20220707215330478" style="zoom:50%;"><p>注意看，两个机房的存储层都互相同步数据的。有了数据同步中间件，就可以达到这样的效果：</p><ul><li>北京机房写入 X = 1</li><li>上海机房写入 Y = 2</li><li>数据通过中间件双向同步</li><li>北京、上海机房都有 X = 1、Y = 2 的数据</li></ul><p>这里我们用中间件双向同步数据，就不用再担心专线问题，专线出问题，我们的中间件可以自动重试，直到成功，达到数据最终一致。</p><p>但这里还会遇到一个问题，两个机房都可以写，操作的不是同一条数据那还好，如果修改的是同一条的数据，发生冲突怎么办？</p><ul><li>用户短时间内发了 2 个修改请求，都是修改同一条数据</li><li>一个请求落在北京机房，修改 X = 1（还未同步到上海机房）</li><li>另一个请求落在上海机房，修改 X = 2（还未同步到北京机房）</li><li>两个机房以哪个为准？</li></ul><p>也就是说，在很短的时间内，同一个用户修改同一条数据，两个机房无法确认谁先谁后，数据发生「冲突」。</p><p>这是一个很严重的问题，系统发生故障并不可怕，可怕的是数据发生「错误」，因为修正数据的成本太高了。我们一定要避免这种情况的发生。解决这个问题，有 2 个方案。</p><p><strong>第一个方案</strong>，数据同步中间件要有自动「合并」数据、解决「冲突」的能力。</p><p>这个方案实现起来比较复杂，要想合并数据，就必须要区分出「先后」顺序。我们很容易想到的方案，就是以「时间」为标尺，以「后到达」的请求为准。</p><p>但这种方案需要两个机房的「时钟」严格保持一致才行，否则很容易出现问题。例如：</p><ul><li>第 1 个请求落到北京机房，北京机房时钟是 10:01，修改 X = 1</li><li>第 2 个请求落到上海机房，上海机房时钟是 10:00，修改 X = 2</li></ul><p>因为北京机房的时间「更晚」，那最终结果就会是 X = 1。但这里其实应该以第 2 个请求为准，X = 2 才对。</p><p>可见，完全「依赖」时钟的冲突解决方案，不太严谨。</p><p>所以，通常会采用<strong>第二种方案</strong>，从「<strong>源头</strong>」就避免数据冲突的发生。</p><h2 id="_10-如何实施异地双活" tabindex="-1">10 如何实施异地双活 <a class="header-anchor" href="#_10-如何实施异地双活" aria-label="Permalink to &quot;10 如何实施异地双活&quot;">​</a></h2><p>既然自动合并数据的方案实现成本高，那我们就要想，能否从源头就「避免」数据冲突呢？</p><p>这个思路非常棒！</p><p>从源头避免数据冲突的思路是：<strong>在最上层接入流量时，就不要让冲突的情况发生。</strong></p><p>具体来讲就是，要在最上层就把用户「区分」开，部分用户请求固定打到北京机房，其它用户请求固定打到上海 机房，进入某个机房的用户请求，之后的所有业务操作，都在这一个机房内完成，从根源上避免「跨机房」。</p><p>所以这时，你需要在接入层之上，再部署一个「路由层」（通常部署在云服务器上），自己可以配置路由规则，把用户「分流」到不同的机房内。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.30/202207072151014.png" alt="image-20220707215145904" style="zoom:50%;"><p>但这个路由规则，具体怎么定呢？有很多种实现方式，最常见的我总结了 3 类：</p><ol><li>按业务类型分片</li><li>直接哈希分片</li><li>按地理位置分片</li></ol><p><strong>1、按业务类型分片</strong></p><p>这种方案是指，按应用的「业务类型」来划分。</p><p>举例：假设我们一共有 4 个应用，北京和上海机房都部署这些应用。但应用 1、2 只在北京机房接入流量，在上海机房只是热备。应用 3、4 只在上海机房接入流量，在北京机房是热备。</p><p>这样一来，应用 1、2 的所有业务请求，只读写北京机房存储，应用 3、4 的所有请求，只会读写上海机房存储。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.30/202207072152233.png" alt="image-20220707215216118" style="zoom:50%;"><p>这样按业务类型分片，也可以避免同一个用户修改同一条数据。</p><blockquote><p>这里按业务类型在不同机房接入流量，还需要考虑多个应用之间的依赖关系，要尽可能的把完成「相关」业务的应用部署在同一个机房，避免跨机房调用。</p><p>例如，订单、支付服务有依赖关系，会产生互相调用，那这 2 个服务在 A 机房接入流量。社区、发帖服务有依赖关系，那这 2 个服务在 B 机房接入流量。</p></blockquote><p><strong>2、直接哈希分片</strong></p><p>这种方案就是，最上层的路由层，会根据用户 ID 计算「哈希」取模，然后从路由表中找到对应的机房，之后把请求转发到指定机房内。</p><p>举例：一共 200 个用户，根据用户 ID 计算哈希值，然后根据路由规则，把用户 1 - 100 路由到北京机房，101 - 200 用户路由到上海机房，这样，就避免了同一个用户修改同一条数据的情况发生。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.30/202207072152821.png" alt="image-20220707215240709" style="zoom:50%;"><p><strong>3、按地理位置分片</strong></p><p>这种方案，非常适合与地理位置密切相关的业务，例如打车、外卖服务就非常适合这种方案。</p><p>拿外卖服务举例，你要点外卖肯定是「就近」点餐，整个业务范围相关的有商家、用户、骑手，它们都是在相同的地理位置内的。</p><p>针对这种特征，就可以在最上层，按用户的「地理位置」来做分片，分散到不同的机房。</p><p>举例：北京、河北地区的用户点餐，请求只会打到北京机房，而上海、浙江地区的用户，请求则只会打到上海机房。这样的分片规则，也能避免数据冲突。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.30/202207072153389.png" alt="image-20220707215302269" style="zoom:50%;"><blockquote><p>提醒：这 3 种常见的分片规则，第一次看不太好理解，建议配合图多理解几遍。搞懂这 3 个分片规则，你才能真正明白怎么做异地多活。</p></blockquote><p>总之，分片的核心思路在于，<strong>让同一个用户的相关请求，只在一个机房内完成所有业务「闭环」，不再出现「跨机房」访问。</strong></p><p>阿里在实施这种方案时，给它起了个名字，叫做「<strong>单元化</strong>」。</p><blockquote><p>当然，最上层的路由层把用户分片后，理论来说同一个用户只会落在同一个机房内，但不排除程序 Bug 导致用户会在两个机房「漂移」。</p><p>安全起见，每个机房在写存储时，还需要有一套机制，能够检测「数据归属」，应用层操作存储时，需要通过中间件来做「兜底」，避免不该写本机房的情况发生。（篇幅限制，这里不展开讲，理解思路即可）</p></blockquote><p>现在，两个机房就可以都接收「读写」流量（做好分片的请求），底层存储保持「双向」同步，两个机房都拥有全量数据，当任意机房故障时，另一个机房就可以「接管」全部流量，实现快速切换，简直不要太爽。</p><p>不仅如此，因为机房部署在异地，我们还可以更细化地「优化」路由规则，让用户访问就近的机房，这样整个系统的性能也会大大提升。</p><blockquote><p>这里还有一种情况，是无法做数据分片的：<strong>全局数据</strong>。例如系统配置、商品库存这类需要强一致的数据，这类服务依旧只能采用写主机房，读从机房的方案，不做双活。</p><p>双活的重点，是要优先保证「核心」业务先实现双活，并不是「全部」业务实现双活。</p></blockquote><p>至此，我们才算实现了真正的「<strong>异地双活</strong>」！</p><blockquote><p>到这里你可以看出，完成这样一套架构，需要投入的成本是巨大的。</p><p>路由规则、路由转发、数据同步中间件、数据校验兜底策略，不仅需要开发强大的中间件，同时还要业务配合改造（业务边界划分、依赖拆分）等一些列工作，没有足够的人力物力，这套架构很难实施。</p></blockquote><h2 id="_11-异地多活" tabindex="-1">11 异地多活 <a class="header-anchor" href="#_11-异地多活" aria-label="Permalink to &quot;11 异地多活&quot;">​</a></h2><p>同城双活无法做到城市级别的容灾。所以需要考虑异地多活。</p><p>比如上海的服务器宕机了，还有重庆的服务器可以顶上来。但两地距离不要太近，因为发生自然灾害时有可能会被另外一地波及到。</p><p>和同城双活的核心思想一样，避免跨机房调用。但是因为异地方案中的调用延迟远大于同机房的方案，所以数据同步是一个非常值得探讨的点。提供两种方案：</p><ul><li>基于存储系统的主从复制，MySQL 和 Redis 天生就具备。但是数据量很大的情况下，性能是较差的。</li><li>异步复制的方式。基于消息队列，将数据操作作为一个消息放到消息队列，另外的机房消费这条消息，操作存储组件。</li></ul><p>理解了异地双活，那「异地多活」顾名思义，就是在异地双活的基础上，部署多个机房即可。架构变成了这样：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.30/202207072149515.png" alt="image-20220707214958438" style="zoom:67%;"><p>这些服务按照「单元化」的部署方式，可以让每个机房部署在任意地区，随时扩展新机房，你只需要在最上层定义好分片规则就好了。</p><p>但这里还有一个小问题，随着扩展的机房越来越多，当一个机房写入数据后，需要同步的机房也越来越多，这个实现复杂度会比较高。</p><p>所以业界又把这一架构又做了进一步优化，把「网状」架构升级为「星状」：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.30/202207072151675.png" alt="image-20220707215122563" style="zoom:67%;"><p>这种方案必须设立一个「中心机房」，任意机房写入数据后，都只同步到中心机房，再由中心机房同步至其它机房。</p><p>这样做的好处是，一个机房写入数据，只需要同步数据到中心机房即可，不需要再关心一共部署了多少个机房，实现复杂度大大「简化」。</p><p>但与此同时，这个中心机房的「稳定性」要求会比较高。不过也还好，即使中心机房发生故障，我们也可以把任意一个机房，提升为中心机房，继续按照之前的架构提供服务。</p><p>至此，我们的系统彻底实现了「<strong>异地多活</strong>」！</p><p>多活的优势在于，<strong>可以任意扩展机房「就近」部署。任意机房发生故障，可以完成快速「切换」</strong>，大大提高了系统的可用性。</p><p>同时，我们也再也不用担心系统规模的增长，因为这套架构具有极强的「<strong>扩展能力</strong>」。</p><p>怎么样？我们从一个最简单的应用，一路优化下来，到最终的架构方案，有没有帮你彻底理解异地多活呢？</p><h2 id="总结" tabindex="-1">总结 <a class="header-anchor" href="#总结" aria-label="Permalink to &quot;总结&quot;">​</a></h2><p>不论使用哪种方式，都涉及到跨机房数据传输延迟的问题。</p><ul><li>同地多机房专线，延迟 1ms~3 ms。</li><li>异地多机房专线，延迟 50 ms 左右。</li><li>跨国多机房，延迟 200 ms 左右。</li></ul><p>好了，总结一下这篇文章的重点。</p><p>1、一个好的软件架构，应该遵循高性能、高可用、易扩展 3 大原则，其中「高可用」在系统规模变得越来越大时，变得尤为重要</p><p>2、系统发生故障并不可怕，能以「最快」的速度恢复，才是高可用追求的目标，异地多活是实现高可用的有效手段</p><p>3、提升高可用的核心是「冗余」，备份、主从副本、同城灾备、同城双活、两地三中心、异地双活，异地多活都是在做冗余</p><p>4、同城灾备分为「冷备」和「热备」，冷备只备份数据，不提供服务，热备实时同步数据，并做好随时切换的准备</p><p>5、同城双活比灾备的优势在于，两个机房都可以接入「读写」流量，提高可用性的同时，还提升了系统性能。虽然物理上是两个机房，但「逻辑」上还是当做一个机房来用</p><p>6、两地三中心是在同城双活的基础上，额外部署一个异地机房做「灾备」，用来抵御「城市」级别的灾害，但启用灾备机房需要时间</p><p>7、异地双活才是抵御「城市」级别灾害的更好方案，两个机房同时提供服务，故障随时可切换，可用性高。但实现也最复杂，理解了异地双活，才能彻底理解异地多活</p><p>8、异地多活是在异地双活的基础上，任意扩展多个机房，不仅又提高了可用性，还能应对更大规模的流量的压力，扩展性最强，是实现高可用的最终方案</p><h2 id="后记" tabindex="-1">后记 <a class="header-anchor" href="#后记" aria-label="Permalink to &quot;后记&quot;">​</a></h2><p>这篇文章我从「宏观」层面，向你介绍了异地多活架构的「核心」思路，整篇文章的信息量还是很大的，如果不太好理解，我建议你多读几遍。</p><p>因为篇幅限制，很多细节我并没有展开来讲。这篇文章更像是讲异地多活的架构之「道」，而真正实施的「术」，要考虑的点其实也非常繁多，因为它需要开发强大的「基础设施」才可以完成实施。</p><p>不仅如此，要想真正实现异地多活，还需要遵循一些原则，例如业务梳理、业务分级、数据分类、数据最终一致性保障、机房切换一致性保障、异常处理等等。同时，相关的运维设施、监控体系也要能跟得上才行。</p><p>宏观上需要考虑业务（微服务部署、依赖、拆分、SDK、Web 框架）、基础设施（服务发现、流量调度、持续集成、同步中间件、自研存储），微观上要开发各种中间件，还要关注中间件的高性能、高可用、容错能力，其复杂度之高，只有亲身参与过之后才知道。</p><p>我曾经有幸参与过，存储层同步中间件的设计与开发，实现过「跨机房」同步 MySQL、Redis、MongoDB 的中间件，踩过的坑也非常多。当然，这些中间件的设计思路也非常有意思，有时间单独分享一下这些中间件的设计思路。</p><p>值得提醒你的是，只有真正理解了「异地双活」，才能彻底理解「异地多活」。在我看来，从同城双活演变为异地双活的过程，是最为复杂的，最核心的东西包括，<strong>业务单元化划分、存储层数据双向同步、最上层的分片逻辑</strong>，这些是实现异地多活的重中之重。</p><h1 id="高可用分析" tabindex="-1">高可用分析 <a class="header-anchor" href="#高可用分析" aria-label="Permalink to &quot;高可用分析&quot;">​</a></h1><p><a href="https://mp.weixin.qq.com/s?__biz=MzU1Nzg4NjgyMw==&amp;mid=2247498143&amp;idx=2&amp;sn=137a83ca7b4d90ad904100944be34d7a&amp;chksm=fc2c4597cb5bcc81d007dc6733e39d622cfbaed0a2f8c1707dcb6a51417a77ee759eb2bc401f&amp;mpshare=1&amp;scene=23&amp;srcid=0511nofXIwVjAaZEqcFMxEHx&amp;sharer_sharetime=1652199731642&amp;sharer_shareid=29b8a04db1dbd975e3bf4e9f47e7ac67#rd" target="_blank" rel="noreferrer">你管这破玩意儿叫高可用？ (qq.com)</a></p><p>大家好，今天我们来聊一下互联网三高（高并发、高性能、高可用）中的高可用，看完本文相信能解开你关于高可用设计的大部分困惑。</p><h2 id="前言" tabindex="-1">前言 <a class="header-anchor" href="#前言" aria-label="Permalink to &quot;前言&quot;">​</a></h2><p>高可用（High availability，即 HA）的主要目的是为了<code>保障「业务的连续性」</code>，即在用户眼里，业务永远是正常（或者说基本正常）对外提供服务的。高可用主要是针对架构而言，那么要做好高可用，就要首先设计好架构，第一步我们一般会采用<code>分层的思想将一个庞大的 IT 系统拆分成为应用层，中间件，数据存储层等独立的层</code>，每一层再拆分成为更细粒度的组件，第二步就是让每个组件对外提供服务，毕竟每个组件都不是孤立存在的，都需要互相协作，对外提供服务才有意义。</p><p>要保证架构的高可用，就要保证架构中所有组件以及其对外暴露服务都要做高可用设计，任何一个组件或其服务没做高可用，都意味着系统存在风险。</p><p>那么这么多组件该怎么做高可用设计呢，其实任何组件要做高可用，都离不开<code>「冗余」和「自动故障转移」</code>，众所周知<code>单点是高可用的大敌</code>，所以组件一般是以集群（至少两台机器）的形式存在的，这样只要某台机器出现问题，集群中的其他机器就可以随时顶替，这就是「冗余」。简单计算一下，<code>假设一台机器的可用性为 90%，则两台机器组成的集群可用性为 1-0.1*0.1 = 99%，所以显然冗余的机器越多，可用性越高</code>。</p><p>但光有冗余还不够，如果机器出现问题，需要人工切换的话也是费时费力，而且容易出错，所以我们<code>还需要借助第三方工具（即仲裁者）的力量来实现「自动」的故障转移</code>，以达到实现<strong>近实时</strong>的故障转移的目的，<strong>近实时的故障转移才是高可用的主要意义</strong></p><p>怎样的系统可以称之为高可用呢，业界一般用几个九来衡量系统的可用性，如下</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5.13/202205131546137.png" alt="image-20220513154643064" style="zoom:80%;"><p>一般实现两个 9 很简单，毕竟每天宕机 14 分钟已经严重影响业务了，这样的公司迟早歇菜，大厂一般要求 4 个 9，其他要求严苛的业务要达到五个九以上，比如如果因为一个电脑的故障导致所有列车停驶，那么就会有数以万计的人正常生活受到阻碍，这种情况就要求五个九以上</p><p>接下来我们就来一起看看架构中的各个组件如何借助「冗余」和「自动故障转移」来实现高可用。</p><h2 id="互联网架构剖析" tabindex="-1">互联网架构剖析 <a class="header-anchor" href="#互联网架构剖析" aria-label="Permalink to &quot;互联网架构剖析&quot;">​</a></h2><p>目前多数互联网都会采用微服务架构，常见架构如下:</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5.13/202205131547150.png" alt="image-20220513154753061" style="zoom:80%;"><p>可以看到架构主要分以下几层</p><ol><li>接入层：主要由 F5 硬件或 LVS 软件来承载所有的流量入口</li><li>反向代理层：Nginx，主要负责根据 url 来分发流量，限流等</li><li>网关：主要负责流控，风控，协议转换等</li><li>站点层：主要负责调用会员，促销等基本服务来装配 json 等数据并返回给客户端</li><li>基础 service：其实与站点层都属于微服务，是平级关系，只不过基础 service 属于基础设施，能被上层的各个业务层 server 调用而已</li><li>存储层：也就是 DB，如 MySQL，Oracle 等，一般由基础 service 调用返回给站点层</li><li>中间件：ZK，ES，Redis，MQ 等，主要起到加速访问数据等功能，在下文中我们会简单介绍下各个组件的作用</li></ol><p>如前所述，要实现整体架构的高可用，必须要实现每一层组件的高可用，接下来我们就来分别看一下每一层的组件都是如何实现高可用的</p><h2 id="接入层-反向代理层" tabindex="-1">接入层&amp;反向代理层 <a class="header-anchor" href="#接入层-反向代理层" aria-label="Permalink to &quot;接入层&amp;反向代理层&quot;">​</a></h2><p>这两层的高可用都和 keepalived 有关，所以我们结合起来一起看</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5.13/202205131549243.png" alt="image-20220513154936156" style="zoom:80%;"><p>对外，两个 LVS 以主备的形式对外提供服务，注意只有 master 在工作（即此时的 VIP 在 master 上生效），另外一个 backup 在 master 宕机之后会接管 master 的工作，那么 backup 怎么知道 master 是否正常呢，答案是<code>通过 keepalived，在主备机器上都装上 keepalived 软件，启动后就会通过心跳检测彼此的健康状况，一旦 master 宕机，keepalived 会检测到，从而 backup 自动转成 master 对外提供服务，此时 VIP 地址（即图中的 115.204.94.139）即在 backup 上生效，也就是我们常说的「IP漂移」</code>，通过这样的方式即解决了 LVS 的高可用。</p><p>keepalived 的心跳检测主要通过发送 ICMP 报文，或者利用 TCP 的端口连接和扫描检测来检测的，同样的，它也可以用来检测 Nginx 暴露的端口，这样的话如果某些 Nginx 不正常 Keepalived 也能检测到并将其从 LVS 能转发的服务列表中剔出。Nginx也能通过端口检测服务健康状态</p><p>借用 keepalived 这个第三方工具，同时实现了 LVS 和 Nginx 的高可用，同时在出现故障时也可以将宕机情况发送到对应开发人员的邮箱以让他们及时收到通知处理，确实很方便，Keepalived 应用广泛，下文我们会看到它也可以用在 MySQL 上来实现 MySQL 的高可用。</p><h2 id="微服务" tabindex="-1">微服务 <a class="header-anchor" href="#微服务" aria-label="Permalink to &quot;微服务&quot;">​</a></h2><p>接下来我们再来看一下「网关」，「站点层」,「基础服务层」，这三者一般就是我们所说的微服务架构组件，当然这些微服务组件还需要通过一些 RPC 框架如 Dubbo 来支撑才能通信，所以微服务要实现高可用，就意味着 dubbo 这些 RPC 框架也要提供支撑微服务高可用的能力，我们就以 dubbo 为例来看下它是如何实现高可用的</p><p>我们先来简单地看下 dubbo 的基本架构</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5.13/202205131552784.png" alt="image-20220513155236717" style="zoom:67%;"><p>思路也很简单，首先是 Provider（服务提供者）向 Registry（注册中心，如 ZK 或 Nacos 等）注册服务，然后 Consumer（服务消费者）向注册中心订阅和拉取 Provider 服务列表，获取服务列表后，Consumer 就可以根据其负载均衡策略选择其中一个 Provider 来向其发出请求，当其中某个 Provider 不可用（下线或者因为 GC 阻塞等）时，会被注册中心及时监听（通过心跳机制）到，也会及时推送给 Consumer，这样 Consumer 就能将其从可用的 Provider 列表中剔除，也就实现了故障的自动转移，不难看出，注册中心就起到了类似 keepalived 的作用</p><h2 id="中间件" tabindex="-1">中间件 <a class="header-anchor" href="#中间件" aria-label="Permalink to &quot;中间件&quot;">​</a></h2><p>我们再来看下这些中间件如 ZK，Redis 等是如何实现高可用的呢</p><h3 id="zookeeper" tabindex="-1">ZooKeeper <a class="header-anchor" href="#zookeeper" aria-label="Permalink to &quot;ZooKeeper&quot;">​</a></h3><p>上一节微服务中我们提到了注册中心，那我们就以 ZK（ZooKeeper）为例来看看它的高可用是如何实现的，先来看下它的整体架构图如下</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5.13/202205131556288.png" alt="image-20220513155602203" style="zoom:80%;"><p>Zookeeper 中的主要角色如下</p><ul><li>Leader: 即领导者，在集群中只有一个 Leader，主要承担了以下的功能</li></ul><ol><li><code>事务请求的唯一调度和处理者，保证集群事务处理的顺序性</code>，所有 Follower 的写请求都会转给 Leader 执行，用来保证事务的一致性</li><li><code>集群内部各服务器的调度者：处理好事务请求后，会将数据广播同步到各个 Follower，统计 Follower 写入成功的数量，超过半数 Follower 写入成功，Leader 就会认为写请求提交成功，通知所有的 Follower commit 这个写操作，保证事后哪怕是集群崩溃恢复或者重启</code>，这个写操作也不会丢失。</li></ol><ul><li>Follower:</li></ul><ol><li><code>处理客户端非事务请求、转发事务请求给 leader 服务器</code></li><li><code>参与事物请求 Proposal 的投票（需要半数以上服务器通过才能通知 leader commit 数据; Leader 发起的提案，要求 Follower 投票）</code></li><li>参与 Leader 选举的投票</li></ol><p><strong>画外音</strong>：Zookeeper 3.0 之后新增了一种 Observer 的角色，不过与此处讨论的 ZK 高可用关系不是很大，为了简化问题，所以省略</p><p>可以看到由于只有一个 Leader，很显然，此 Leader 存在单点隐患，那么 ZK 是怎么解决此问题的呢，首先 Follower 与 Leader 会用心跳机制保持连接，如果 Leader 出现问题了（宕机或者因为 FullGC 等原因无法响应），Follower 就无法感知到 Leader 的心跳，就会认为 Leader 出问题了，于是它们就会发起投票选举，最终在多个 Follower 中选出一个 Leader 来（这里主要用到了 Zookeeper Atomic Broadcast，即 ZAB 协议，它是为 ZK 专门设计的一种支持崩溃恢复的一致性协议），选举的细节不是本文重点，就不在此详述了。</p><p><code>除了 ZAB 协议，业界上常用的还有 Paxos，Raft 等协议算法，也可以用在 Leader 选举上，也就是是在分布式架构中，这些协议算法承担了“第三者”也就是仲裁者的作用，以承担故障的自动转移</code></p><h3 id="redis" tabindex="-1">Redis <a class="header-anchor" href="#redis" aria-label="Permalink to &quot;Redis&quot;">​</a></h3><p>Redis 的高可用需要根据它的部署模式来看看，主要分为「主从模式」和「Cluster 分片模式」两种</p><h4 id="主从模式" tabindex="-1">主从模式 <a class="header-anchor" href="#主从模式" aria-label="Permalink to &quot;主从模式&quot;">​</a></h4><p>先来看一下主从模式，架构如下</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5.13/202205131558789.png" alt="image-20220513155811708" style="zoom:67%;"><p>主从模式即一主多从（一个或者多个从节点），其<code>中主节点主要负责读和写，然后会将数据同步到多个从节点上，Client 也可以对多个从节点发起读请求，这样可以减轻主节点的压力</code>，但和 ZK 一样，由于只有一个主节点，存在单点隐患，所以必须引入第三方仲裁者的机制来判定主节点是否宕机以及在判定主节点宕机后快速选出某个从节点来充当主节点的角色，这个第三方仲裁者在 Redis 中我们一般称其为「哨兵」（sentinel），当然哨兵进程本身也有可能挂掉，所以为了安全起见，需要部署多个哨兵（即哨兵集群）</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5.13/202205131558455.png" alt="image-20220513155845360" style="zoom:50%;"><p>这些哨兵通过 gossip（流言） 协议来接收关于主服务器是否下线的信息，并在判定主节点宕机后使用 Raft 协议来选举出新的主节点</p><h4 id="cluster-分片集群" tabindex="-1">Cluster 分片集群 <a class="header-anchor" href="#cluster-分片集群" aria-label="Permalink to &quot;Cluster 分片集群&quot;">​</a></h4><p>主从模式看似完美，但存在以下几个问题</p><ol><li>主节点写的压力难以降低：因为只有一个主节点能接收写请求，如果在高并发的情况下，写请求如果很高的话可能会把主节点的网卡打满，造成主节点对外无法服务</li><li>主节点的存储能力受到单机存储容量的限制：因为不管是主节点还是从节点，存储的都是<strong>全量</strong>缓存数据，那么随着业务量的增长，缓存数据很可能直线上升，直到达到存储瓶颈</li><li>同步风暴：因为数据都是从 master 同步到 slave 的，如果有多个从节点的话，master 节点的压力会很大</li></ol><p>为了解决主从模式的以上问题，分片集群应运而生，所谓分片集群即将数据分片，每一个分片数据由相应的主节点负责读写，这样的话就有多个主节点来分担写的压力，并且每个节点只存储<strong>部分数据</strong>，也就解决了单机存储瓶颈的问题，但需要注意的是每个主节点都存在单点问题，所以需要针对每个主节点做高可用，整体架构如下</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5.13/202205131600279.png" alt="image-20220513160051180" style="zoom:67%;"><p>原理也很简单，在 Proxy 收到 client 执行的 redis 的读写命令后，首先会对 key 进行计算得出一个值，如果这个值落在相应 master 负责的数值范围（一般将每个数字称为槽，Redis 一共有 16384 个槽）之内，那就把这条 redis 命令发给对应的 master 去执行，可以看到每个 master 节点只负责处理一部分的 redis 数据，同时为了避免每个 master 的单点问题，也为其配备了多个从节点以组成集群，当主节点宕机时，集群会通过 Raft 算法来从从节点中选举出一个主节点</p><h3 id="elasticsearch" tabindex="-1">ElasticSearch <a class="header-anchor" href="#elasticsearch" aria-label="Permalink to &quot;ElasticSearch&quot;">​</a></h3><p>再来看一下 ES 是如何实现高可用的，在 ES 中，数据是以分片（Shard）的形式存在的，如下图所示，一个节点中索引数据共分为三个分片存储</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5.13/202205131602879.png" alt="image-20220513160216809" style="zoom:80%;"><p>但只有一个节点的话，显然存在和 Redis 的主从架构一样的单点问题，这个节点挂了，ES 也就挂了，所以显然需要创建多个节点</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5.13/202205131602397.png" alt="image-20220513160235312" style="zoom:67%;"><p>一旦创建了多个节点，分片（图中 P 为主分片，R 为副本分片）的优势就体现出来了，可以将分片数据分布式存储到其它节点上，极大提升了数据的水平扩展能力，同时每个节点都能承担读写请求，采用负载均衡的形式避免了单点的读写压力</p><blockquote><p>ES 的写机制与 Redis 和 MySQL 的主从架构有些差别（后两者的写都是直接向 master 节点发起写请求，而 ES 则不是），所以这里稍微解释一下 ES 的工作原理</p><p>首先说下节点的工作机制，节点（Node）分为主节点（Master Node）和从结点（Slave Node），主节点的主要职责是负责集群层面的相关操作，管理集群变更，如创建或删除索引，跟踪哪些节点是集群的一部分，并决定哪些分片分配给相关的节点，主节点也只有一个，一般通过类 Bully 算法来选举出来，如果主节点不可用了，则其他从节点也可以通过此算法来选举以实现集群的高可用，任何节点都可以接收读写请求以达到负载均衡的目的</p><p>再说一下分片的工作原理，分片分为主分片（Primary Shard，即图中 P0，P1，P2）和副本分片（Replica Shard，即图中 R0，R1，R2），主分片负责数据的写操作，所以虽然任何节点可以接收读写请求，但如果此节点接收的是写请求并且没有写数据所在的主分片话，此节点会将写请求调度到主分片所在的节点上，写入主分片后，主分片再把数据复制到其他节点的副本分片上，以有两个副本的集群为例，写操作如下</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5.13/202205131604600.png" alt="image-20220513160400528" style="zoom:67%;"><h3 id="mq" tabindex="-1">MQ <a class="header-anchor" href="#mq" aria-label="Permalink to &quot;MQ&quot;">​</a></h3><p>ES 利用数据分片来提升高可用和水平扩展能力的思想也应用在其他组件的架构设计上，我们以 MQ 中的 Kafka 为例再来看下数据分片的应用</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5.13/202205131604249.png" alt="image-20220513160439148" style="zoom:67%;"><p>如上是 Kafka 集群，可以看到每个 Topic 的 Partition 都分布式存储在其它消息服务器上，这样一旦某个 Partition 不可用，可以从 follower 中选举出 leader 继续服务，不过与 ES 中的数据分片不同的是，follower Partition 属于<strong>冷备</strong>，也就是说在正常情况下不会对外服务，只有在 leader 挂掉之后从 follower 中选举出 leader 后它才能对外提供服务</p><h2 id="存储层" tabindex="-1">存储层 <a class="header-anchor" href="#存储层" aria-label="Permalink to &quot;存储层&quot;">​</a></h2><p>接下来我们再来看一下最后一层，存储层（DB），这里我们以 MySQL 为例来简单地讨论一下其高可用设计，其实大家如果看完了以上的高可用设计，会发现 MySQL 的高可用也不过如此，思想都是类似的，与 Redis 类似，它也分主从和分片（即我们常说的分库分表）两种架构</p><p>主从的话与 LVS 类似，一般使用 keepalived 的形式来实现高可用，如下所示</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5.13/202205131607111.png" alt="image-20220513160723030" style="zoom:67%;"><p>如果 master 宕机了，Keepalived 也会及时发现，于是从库会升级主库，并且 VIP 也会“漂移”到原从库上生效，所以说大家在工程配置的 MySQL 地址一般是 VIP 以保证高可用</p><p>数据量大了之后就要分库分表了，于是就有了多主，就像 Redis 的分片集群一样，需要针对每个主配备多个从，如下</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5.13/202205131611841.png" alt="image-20220513161139765" style="zoom:80%;"><p>之前有读者问分库分表之后为啥还要做主从，现在我想大家应该都明白了，不是为了解决读写性能问题，主要是为了实现高可用</p><h2 id="总结-1" tabindex="-1">总结 <a class="header-anchor" href="#总结-1" aria-label="Permalink to &quot;总结&quot;">​</a></h2><p>看完了架构层面的高可用设计，相信大家对高可用的核心思想<code>「冗余」和「自动故障转移」</code>会有更深刻的体会，观察以上架构中的组件你会发现冗余的主要原因是因为只有一主，<code>为什么不能有多主呢，也不是不可以，但这样在分布式系统下要保证数据的一致性是非常困难的，尤其是节点多了的话，数据之间的同步更是一大难题，所以多数组件采用一主的形式，然后再在主和多从之间同步，多数组件之所以选择一主本质上是技术上的 tradeoff</code></p><p>那么做好每个组件的高可用之后是否整个架构就真的可用了呢，非也，这只能说迈出了第一步，在生产上还有很多突发情况会让我们的系统面临挑战，比如</p><ol><li><code>瞬时流量问题</code>：比如我们可能会面临秒杀带来的瞬时流量激增导致系统的承载能力被压垮，这种情况可能影响日常交易等核心链路，所以需要做到系统之间的隔离，如单独为秒杀部署一套独立的集群</li><li><code>安全问题</code>：比如 DDOS 攻击，爬虫频繁请求甚至删库跑路等导致系统拒绝服务</li><li><code>代码问题</code>：比如代码 bug 引起内存泄露导致 FullGC 导致系统无法响应等</li><li><code>部署问题</code>：在发布过程中如果贸然中止当前正在运行的服务也是不行的，需要做到优雅停机，平滑发布</li><li><code>第三方问题</code>：比如我们之前的服务依赖第三方系统，第三方可能出问题导致影响我们的核心业务</li><li><code>不可抗力</code>：如机房断电，所以需要做好容灾，异地多活，之前我司业务就由于机房故障导致服务四小时不可用，损失惨重</li></ol><p>所以除了做好架构的高可用之外，我们还需要在做好<code>系统隔离，限流，熔断，风控，降级，</code>对关键操作限制操作人权限等措施以保证系统的可用。</p><p>这里<code>特别提一下降级</code>，这是为了保证系统可用性采取的常用的措施，简单举几个例子</p><ol><li>我们之前对接过一个第三方资金方由于自身原因借款功能出了问题导致无法借款，这种情况为了避免引起用户恐慌，于是我们在用户申请第三方借款的时候返回了一个类似<code>「为了提升你的额度，资金方正在系统升级」</code>这样的文案，避免了客诉</li><li>在流媒体领域，<code>当用户观看直播出现严重卡顿时，很多企业的第一选择不是查 log 排查问题，而是为用户自动降码率。因为比起画质降低，卡得看不了显然会让用户更痛苦</code></li><li>双十一零点高峰期，我们<code>把用户的注册登录等非核心功能给停掉了，以保证下单等核心流程的顺利</code></li></ol><p>另外我们最好能做到<code>事前防御</code>，在系统出问题前把它扼杀在摇篮里，所以我们需要做单元测试，做<code>全链路压测等来发现问题，还需要针对 CPU，线程数等做好**监控**，当其达到我们设定的域值时就触发告警以让我们及时发现修复问题</code>（我司之前就碰到过一个类似的<a href="https://mp.weixin.qq.com/s?__biz=MzI5MTU1MzM3MQ==&amp;mid=2247483844&amp;idx=1&amp;sn=549aabbf5ba5e5f03a634411c630a6da&amp;scene=21#wechat_redirect" target="_blank" rel="noreferrer">生产事故复盘</a>大家可以看一下），此外在做好单元测试的前提下，依然有可能因为代码的潜在 bug 引起线上问题，所以我们需要在关键时间（比如双十一期间）封网（也就是不让发布代码）</p><p>此外我们还需要在出事后能快速定位问题，快速回滚，这就需要记录每一次的发布时间，发布人等，这里的发布不仅包括工程的发布，还包括配置中心等的发布</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5.13/202205131622688.png" alt="image-20220513162211607" style="zoom:80%;"><p><strong>画外音</strong>：上图是我司的发布记录，可以看到有代码变更，回滚等，这样如果发现有问题的话可以一键回滚</p><p>最后我们以一张图来总结一下高可用的常见手段</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5.13/202205131616817.png" alt="image-20220513161638712" style="zoom:80%;"><h1 id="服务雪崩" tabindex="-1">服务雪崩 <a class="header-anchor" href="#服务雪崩" aria-label="Permalink to &quot;服务雪崩&quot;">​</a></h1><p>话说东汉末年，曹操、孙权、刘备在赤壁市进行了一次争夺老大位置的大战，这就是有名的<code>赤壁之战</code>。</p><h2 id="一、还原赤壁之战" tabindex="-1">一、还原赤壁之战 <a class="header-anchor" href="#一、还原赤壁之战" aria-label="Permalink to &quot;一、还原赤壁之战&quot;">​</a></h2><p>曹操统一北方后，南下打败了刘备，占领荆襄之地后，还想干掉东边的孙权，于是刘备和孙权一起联合抗击曹军八十万大军。</p><p>曹操的军队大部分都是北方的，对于水上作战的经验非常欠缺，而且很多士兵晕船，于是曹操命令军队将<code>船尾用铁索相连</code>，减弱了风浪颠簸，利于士兵演练。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202208240929414.png" alt="image-20220824092928335" style="zoom:67%;"><p>我们来看看周瑜、黄盖、诸葛亮的对话：</p><img src="https://mmbiz.qpic.cn/mmbiz_png/SfAHMuUxqJ0UdPhcicMTARoTKVQ8ah7FSbaLhmgcaztUfUVwqGpalGcdHE13eRn9FMC1DE5uraBhJJL5a9LT41Q/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片" style="zoom:67%;"><blockquote><p>黄盖：曹操是真的蠢啊，把船连着，如果船烧着了，其他船会跟着一起烧着的。锁链不易解开，船都逃不了了。我 们用火攻，直接把曹军干趴下。 周瑜：但如何接近他们的船呢？ 黄盖：我用诈降带几艘船出发，船上载浸油的干草，等接近曹军时，点燃干草，冲向曹军的连环船，引燃他们的船 周瑜：妙啊！可是哪来的东风？ 诸葛亮：我来借东风~</p></blockquote><p>赤壁之战那天，火船乘风闯入曹军船阵，顿时一片火海。联军乘势攻击，曹军伤亡惨重，最后以联军大胜结束。以少胜多的经典战役。</p><h2 id="二、战情分析" tabindex="-1">二、战情分析 <a class="header-anchor" href="#二、战情分析" aria-label="Permalink to &quot;二、战情分析&quot;">​</a></h2><p>周瑜和黄盖看出了连环船的弱点：<strong>如果一只船被烧着了，也会把连着的船烧着</strong> 。</p><p>这就很像我们的系统中出现的<code>服务雪崩</code>问题。</p><p>假定我们系统引进了微服务的思想，将多个服务进行拆分，每个服务都是通过接口调用来完成的，看似功能通过微服务化后，功能和职责单一，正是我们想要的.</p><p>但随着业务的增长，服务的数量也是<code>随之增多</code>，逻辑也会<code>更加复杂</code>，一个服务的某个逻辑需要<code>依赖</code>多个其他服务才能完成。假如一个被依赖的服务不能向上游的服务提供服务，则很可能造成<code>雪崩效应</code>，最后导致整个服务<code>不可访问</code>。</p><p>就像雪山上某一处出现积雪崩塌的现象，慢慢地带动其他片区的积雪崩塌，产生了级联反应，最后造成大片的积雪崩塌，这就是常见的雪崩场景。</p><p><strong>小结：</strong> 一个服务失败，导致整条链路的服务都失败的场景，称为服务雪崩。</p><p>那曹军应该怎么避免这个问题呢？别急，后面再看答案。</p><h2 id="三、系统中的雪崩效应" tabindex="-1">三、系统中的雪崩效应 <a class="header-anchor" href="#三、系统中的雪崩效应" aria-label="Permalink to &quot;三、系统中的雪崩效应&quot;">​</a></h2><p>微服务之间往往采用 RPC 或者 HTTP 调用，一般都会设置调用超时的限制，或者通过失败重试机制来确保服务成功执行。但如果不考虑服务的熔断和限流，还是很容易产生服务雪崩的。下面用例子来讲解下雪崩效应是怎么产生的。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202208240932798.png" alt="image-20220824093228691" style="zoom:50%;"><ul><li>我们系统中三个服务：<code>订单服务</code>、<code>商品服务</code>、<code>库存服务</code>。</li><li><strong>下单场景</strong>：用户下单了一个商品，客户端调用订单服务来生成预付款订单，订单服务调用商品服务查看下单的哪款商品，商品服务调用库存服务判断这款商品是否有库存，如有库存，则可以生成预付款订单。</li><li>假定因双十一流量暴增，库存服务不可用（如响应超时等），库存服务收到的很多请求都未处理完，它将无法处理更多请求。</li><li>而上游的商品服务依赖库存服务，商品服务的超时和重试机制会被执行。商品服务新的调用不断产生，会导致商品服务的调用被大量积压，产生大量的调用等待和重试调用，慢慢耗尽商品服务的资源，比如内存，结果导致商品服务也宕机了。</li><li>而订单服务也会重走商品服务的老路。结果就是三个服务都不可用了。</li></ul><h2 id="四、造成雪崩的真实场景" tabindex="-1">四、造成雪崩的真实场景 <a class="header-anchor" href="#四、造成雪崩的真实场景" aria-label="Permalink to &quot;四、造成雪崩的真实场景&quot;">​</a></h2><h3 id="_1-服务提供者不可用" tabindex="-1">1 服务提供者不可用 <a class="header-anchor" href="#_1-服务提供者不可用" aria-label="Permalink to &quot;1 服务提供者不可用&quot;">​</a></h3><ul><li>硬件故障，如网络故障、硬盘损坏等。</li><li>程序的 bug，如算法需要占用大量 CPU 的计算时间导致 CPU 使用率过高。</li><li>缓存击穿：比如应用刚重启，短时间内缓存是失效的，导致大量请求直接访问到了数据库，数据库不堪重负，服务不可用。</li><li>秒杀和大促：服务短时间承载不了那么多请求量。</li></ul><h3 id="_2-重试加大流量" tabindex="-1">2 重试加大流量 <a class="header-anchor" href="#_2-重试加大流量" aria-label="Permalink to &quot;2 重试加大流量&quot;">​</a></h3><ul><li>用户连续重试，比如用户看到界面上没有响应，所以又操作了一遍，结果又增加了一倍请求量。</li><li>程序重试机制，比如代码中有多次重试的逻辑，一次失败后，过几秒后再重试，重试个三次就取消重试，走异常处理分支了。也是增加了请求量。</li></ul><h2 id="五、如何防止雪崩" tabindex="-1">五、如何防止雪崩 <a class="header-anchor" href="#五、如何防止雪崩" aria-label="Permalink to &quot;五、如何防止雪崩&quot;">​</a></h2><p>出问题前预防：限流、主动降级、隔离</p><p>出问题后修复：熔断、被动降级</p><p><strong>本篇主要来讲解熔断机制。</strong></p><h2 id="六、熔断原理和算法" tabindex="-1">六、熔断原理和算法 <a class="header-anchor" href="#六、熔断原理和算法" aria-label="Permalink to &quot;六、熔断原理和算法&quot;">​</a></h2><h3 id="_1-熔断概念" tabindex="-1">1 熔断概念 <a class="header-anchor" href="#_1-熔断概念" aria-label="Permalink to &quot;1 熔断概念&quot;">​</a></h3><p>熔断这个概念来源于电路系统中的<code>保险丝</code>熔断。当电流过大时，保险丝熔断，防止因<code>电流过大</code>损坏电器元器件，或因电流过大，导致元器件热度过高，发生火灾。</p><p><strong>物理公式：</strong> 电功率 P = I^2 * R，I 代表电流，元器件的电阻 R 不变的情况下，电流越大，电功率约大，电阻做的电功大部分都用来<code>发热</code>了，所以电功率越大，发热越严重。（还好高中物理没忘。）</p><p>放到我们系统中，怎么理解熔断？</p><p>如果在某段时间内，调用某个服务非常慢甚至超时，就可以将这个服务熔断，后续其他服务再调用这个服务就直接返回，告诉其他服务：<strong>“已经熔断了，你别调用我了，过段时间再来试下吧。”</strong></p><h3 id="_2-如何熔断" tabindex="-1">2 如何熔断 <a class="header-anchor" href="#_2-如何熔断" aria-label="Permalink to &quot;2 如何熔断&quot;">​</a></h3><p><strong>熔断有个原则：</strong> 一段时间内，统计失败的次数或者失败请求的占比超过一定阈值，就进行熔断。</p><p>详细的原理如下图所示：</p><img src="https://mmbiz.qpic.cn/mmbiz_png/SfAHMuUxqJ0UdPhcicMTARoTKVQ8ah7FSA5JrcEXkklp6PUiaRicPWneFU1pYWPDUiaKwxXWez4E8QUOgnd7CySPwQ/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片" style="zoom:67%;"><h3 id="下面是原理介绍" tabindex="-1"><strong>下面是原理介绍</strong> <a class="header-anchor" href="#下面是原理介绍" aria-label="Permalink to &quot;**下面是原理介绍**&quot;">​</a></h3><h3 id="_3-统计请求的算法" tabindex="-1">3 统计请求的算法 <a class="header-anchor" href="#_3-统计请求的算法" aria-label="Permalink to &quot;3 统计请求的算法&quot;">​</a></h3><ul><li>请求访问到后台服务后，首先判断熔断开关是否打开。</li><li>如果熔断开关已打开，则表明当前请求不能被处理。</li><li>如果熔断开关未打开，则判断时间窗口是否已满。</li><li>如果时间窗口未满，则请求桶中的请求数加 1。</li><li>如果返回的响应有异常，则失败桶的失败数加 1，如果返回的响应没有异常，则成功桶的成功数加 1。</li><li>如果时间窗口（判断统计错误率）已满，则开始判断是否需要熔断。</li></ul><h3 id="_4-熔断的恢复算法" tabindex="-1">4 熔断的恢复算法 <a class="header-anchor" href="#_4-熔断的恢复算法" aria-label="Permalink to &quot;4 熔断的恢复算法&quot;">​</a></h3><ul><li>当熔断后，开关切换到<code>断开状态</code>。</li><li>过一段时间后，开关切换为<code>半断开状态</code>（Half-Open）。半断开状态下，允许对应用程序的一定数量的请求可以去调用服务，如果调用成功，则认为服务可以正常访问了，于是将开关切换为<code>闭合状态</code>。</li><li>如果半断开状态下，还是有调用失败的情况，则认为服务还没有恢复，开关从半断开状态切换到<code>断开状态</code>。</li></ul><h3 id="_5-统计失败率的时间窗口" tabindex="-1">5 统计失败率的时间窗口 <a class="header-anchor" href="#_5-统计失败率的时间窗口" aria-label="Permalink to &quot;5 统计失败率的时间窗口&quot;">​</a></h3><p>时间窗口又分为固定窗口和滑动窗口。</p><p>固定时间窗口：</p><p><strong>原理</strong>：固定时间内统计流量总量，超过阀值则限制流量。</p><p><strong>缺陷</strong>：无法限制短时间之内的集中流量。</p><p>滑动窗口原理：</p><p><strong>原理</strong>：统计的总时间固定，但时间段是滑动的。</p><p><strong>缺陷</strong>：无法控制流量让它们更加平滑</p><p>时间窗口的原理图在这里：</p><img src="https://mmbiz.qpic.cn/mmbiz_png/SfAHMuUxqJ0UdPhcicMTARoTKVQ8ah7FSS44S3wRh5o6Ejj1vtiaQfPiat7sVRNjaOxibr058JxOiaxVcibBNzG1pIqQ/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片" style="zoom:67%;"><ul><li>时间窗口可以比喻为人坐在窗户边，看外面来往的车辆，一定时间内从窗户外经过的车辆。</li><li>每次请求，都会判断时间窗口是否已满（如5分钟），如果时间窗口已满，则重新开始计时，且清理请求数/成功数/失败数。</li><li>注意：第一次开始的起始时间默认为当前时间。</li></ul><h3 id="_6-尝试恢复服务的时间窗口" tabindex="-1">6 尝试恢复服务的时间窗口 <a class="header-anchor" href="#_6-尝试恢复服务的时间窗口" aria-label="Permalink to &quot;6 尝试恢复服务的时间窗口&quot;">​</a></h3><p><img src="https://mmbiz.qpic.cn/mmbiz_png/SfAHMuUxqJ0UdPhcicMTARoTKVQ8ah7FSlKndJG1IEQP19sibovvnxKqxSIMLcMLHukSxUKSDf9ERDSrBXlSial9A/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片" style="zoom:67%;">尝试恢复服务的时间窗口</p><ul><li>开关为断开的状态，经过一定时间后，比如 1 分钟，设置为半断开的状态，尝试发送请求检测服务是否恢复。</li><li>如果已恢复，则切换状态为关闭状态。如果未恢复，则切换状态为断开的状态，经过 1 分钟后，重复上面的步骤。</li><li>这里的时间窗口可以根据环境的运行状态进行动态调整，比如第一次是 1 分钟，第二次是 3 分钟，第三次是 10 分钟。</li></ul><h2 id="七、熔断中间件" tabindex="-1">七、熔断中间件 <a class="header-anchor" href="#七、熔断中间件" aria-label="Permalink to &quot;七、熔断中间件&quot;">​</a></h2><p>肯定有人会问了，你这上面讲的原理，难道还真的自己去写这套算法？</p><p><strong>答案：是的，项目中我们自己造了一个轮子：熔断器。</strong></p><p>但这里我不推荐大家这么做。市面上还有更优秀的开源组件供大家使用，比如阿里系的 <code>Sentinel</code>（推荐），Netflix 的 <code>Hystrix</code>（已停止更新，维护阶段）。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202208240935218.png" alt="image-20220824093502143" style="zoom:67%;"><h2 id="八、扭转战局" tabindex="-1">八、扭转战局 <a class="header-anchor" href="#八、扭转战局" aria-label="Permalink to &quot;八、扭转战局&quot;">​</a></h2><p>曹操大败是因为连锁船的原因，那如何给曹操提供一<code>妙计</code>，助他扭转战局呢？</p><p><strong>方案有如下几个：</strong></p><ul><li>可以用麻绳代替锁链，因绳子更容易割断。（熔断机制）</li><li>将船划分到几个区域，区域之间保持一定距离，即使某个区域烧着了，也不会影响其他区域。（熔断+资源隔离）</li><li>在湖面上提前设关卡，黄盖过来的话，先检查船和人，有问题不予通行。（熔断）</li></ul><h2 id="九、限流、降级" tabindex="-1">九、限流、降级 <a class="header-anchor" href="#九、限流、降级" aria-label="Permalink to &quot;九、限流、降级&quot;">​</a></h2><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202208240935944.png" alt="image-20220824093529893" style="zoom:67%;"><p>对请求的流量进行控制， 只<code>放行部分请求</code>，使服务能够承担不超过自己能力的流量压力。</p><p>常见限流算法有三种：<strong>时间窗口、漏桶算法、令牌桶算法</strong>。</p><h4 id="漏桶算法" tabindex="-1">漏桶算法 <a class="header-anchor" href="#漏桶算法" aria-label="Permalink to &quot;漏桶算法&quot;">​</a></h4><p>原理：按照一个固定的速率将流量露出到接收端。</p><p>缺陷：面对突发流量的时候，采用的解决方式是缓存在漏桶中，这样流量的响应时间就会增长，这就与互联网业务低延迟的要求不符。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202208240935301.png" alt="image-20220824093549239" style="zoom:50%;"><h4 id="令牌桶算法" tabindex="-1">令牌桶算法 <a class="header-anchor" href="#令牌桶算法" aria-label="Permalink to &quot;令牌桶算法&quot;">​</a></h4><p><strong>原理</strong>：一秒内限制访问次数为 N 次。每隔 1/N 的时间，往桶内放入一个令牌。分布式环境下，用 Redis 作为令牌桶。原理图如下：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202208240936987.png" alt="image-20220824093610927" style="zoom:67%;"><p>总结的思维导图在这里：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202208240936843.png" alt="image-20220824093629775" style="zoom:80%;"><h1 id="负载均衡" tabindex="-1">负载均衡 <a class="header-anchor" href="#负载均衡" aria-label="Permalink to &quot;负载均衡&quot;">​</a></h1><h2 id="概念" tabindex="-1">概念 <a class="header-anchor" href="#概念" aria-label="Permalink to &quot;概念&quot;">​</a></h2><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.30/202207020958559.png" alt="image-20220702095830476" style="zoom:50%;"><p>负载均衡的<strong>两个基本点</strong>：</p><ul><li>选择哪个服务器来处理客户端请求。</li><li>将客户端请求转发出去。</li></ul><p><strong>一个核心原理</strong>：通过硬件或软件的方式维护一个服务列表清单。当用户发送请求时，会将请求发送给负载均衡器，然后根据负载均衡算法从可用的服务列表中选出一台服务器的地址，将请求进行转发，完成负载功能。</p><h2 id="负载均衡的特性" tabindex="-1">负载均衡的特性 <a class="header-anchor" href="#负载均衡的特性" aria-label="Permalink to &quot;负载均衡的特性&quot;">​</a></h2><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.30/202207020959765.png" alt="image-20220702095914690" style="zoom:50%;"><p><strong>高性能</strong>：可根据不同的分配规则自动将流量进行分摊。</p><p><strong>可扩展性</strong>：可以很方便增加集群中设备或链路的数量。</p><p><strong>高可靠性</strong>：系统中某个设备或链路发生故障，不会导致服务中断。</p><p><strong>易配置性</strong>：配置和维护方便。</p><p><strong>透明性</strong>：用户感知不到如何进行负载均衡的，也不用关心负载均衡。</p><h2 id="负载均衡分类" tabindex="-1">负载均衡分类 <a class="header-anchor" href="#负载均衡分类" aria-label="Permalink to &quot;负载均衡分类&quot;">​</a></h2><p>负载均衡技术可以按照软件或硬件进行分类，也可以按照服务器列表存放的位置划分为服务端负载和客户端负载均衡。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.30/202207021000921.png" alt="image-20220702100008853" style="zoom:67%;"><h3 id="_1-硬件负载均衡" tabindex="-1">1 硬件负载均衡 <a class="header-anchor" href="#_1-硬件负载均衡" aria-label="Permalink to &quot;1 硬件负载均衡&quot;">​</a></h3><blockquote><p>F5 就是常见的硬件负载均衡产品。</p><p>优点：性能稳定，具备很多软件负载均衡不具备的功能，如应用交换，会话交换、状态监控等。</p><p>缺点：设备价格昂贵、配置冗余，没有软件负载均衡灵活，不能满足定制化需求。</p></blockquote><h3 id="_2-软件负载均衡" tabindex="-1">2 软件负载均衡 <a class="header-anchor" href="#_2-软件负载均衡" aria-label="Permalink to &quot;2 软件负载均衡&quot;">​</a></h3><blockquote><p>Nginx：性能好，可以负载超过 1W。工作在网络的7层之上，可以针对http应用做一些分流的策略。Nginx也可作为静态网页和图片服务器。Nginx仅能支持http、https和Email协议。</p></blockquote><blockquote><p>LVS（Linux Virtual Server）：是一个虚拟服务器集群系统，采用 IP 地址均衡技术和内容请求分发技术实现负载均衡。接近硬件设备的网络吞吐和连接负载能力。抗负载能力强、是工作在网络4层之上仅作分发之用。自身有完整的双机热备方案，如LVS+Keepalived。软件本身不支持正则表达式处理，不能做动静分离。</p></blockquote><h3 id="_3-服务端负载均衡" tabindex="-1">3 服务端负载均衡 <a class="header-anchor" href="#_3-服务端负载均衡" aria-label="Permalink to &quot;3 服务端负载均衡&quot;">​</a></h3><blockquote><p>Nginx 和 F5 都可以划分到服务端的负载均衡里面，后端的服务器地址列表是存储在后端服务器中或者存在专门的 Nginx 服务器或 F5 上。</p></blockquote><blockquote><p>服务器的地址列表的来源是通过注册中心或者手动配置的方式来的。</p></blockquote><h3 id="_4-客户端负载均衡" tabindex="-1">4 客户端负载均衡 <a class="header-anchor" href="#_4-客户端负载均衡" aria-label="Permalink to &quot;4 客户端负载均衡&quot;">​</a></h3><blockquote><p>终于轮到 Ribbon 登场了，它属于客户端负载均衡器，客户端自己维护一份服务器的地址列表。这个维护的工作就是由 Ribbon 来干的。</p></blockquote><blockquote><p>Ribbon 会从 Eureka Server 读取服务信息列表，存储在 Ribbon 中。如果服务器宕机了，Ribbon 会从列表剔除宕机的服务器信息。Ribbon 有多种负载均衡算法，我们可以自行设定规则从而请求到指定的服务器。</p></blockquote></div></div></main><footer class="VPDocFooter" data-v-6b87e69f data-v-37656e44><!--[--><!--]--><!----><nav class="prev-next" data-v-37656e44><div class="pager" data-v-37656e44><a class="pager-link prev" href="/notebook/%E4%B8%89%E9%AB%98/%E7%A7%92%E6%9D%80.html" data-v-37656e44><span class="desc" data-v-37656e44>Previous page</span><span class="title" data-v-37656e44>秒杀</span></a></div><div class="pager" data-v-37656e44><a class="pager-link next" href="/notebook/%E4%B8%89%E9%AB%98/%E9%AB%98%E5%B9%B6%E5%8F%91.html" data-v-37656e44><span class="desc" data-v-37656e44>Next page</span><span class="title" data-v-37656e44>高并发</span></a></div></nav></footer><!--[--><!--]--></div></div></div><!--[--><!--]--></div></div><!----><!--[--><!--]--></div></div>
    <script>window.__VP_HASH_MAP__=JSON.parse("{\"2、数据库_mysql_mysql面试_基础.md\":\"40da680a\",\"1、学前端_5、小程序_小程序项目.md\":\"60a1629b\",\"1、学前端_4、node_知识篇.md\":\"a7fb500e\",\"1、学前端_2、js_ts_es6 进阶.md\":\"6d07ba10\",\"1、学前端_3、vue_vue3_vue3进阶.md\":\"7ac622b4\",\"5、运维_jenkins.md\":\"929081f8\",\"1、学前端_2、js_ts_typescript.md\":\"875a4aa4\",\"2、数据库_mysql_mysql核心_设计.md\":\"7faf46d1\",\"2、数据库_mysql_mysql核心_基础.md\":\"d8e97f3e\",\"1、学前端_1、html_css_html基础.md\":\"7584d076\",\"1、学前端_5、专题篇_问题篇.md\":\"e893aaa2\",\"2、数据库_mysql_mysql面试_进阶.md\":\"f934806d\",\"3、springboot_运维_原理.md\":\"f4a39db6\",\"2、数据库_influxdb.md\":\"6e1711e1\",\"3、springboot_新特性.md\":\"cdf3e307\",\"mybatis_mybatisplus_jpa.md\":\"8e41681b\",\"1、学前端_5、小程序_小程序优化.md\":\"a2185198\",\"2、数据库_redis_redis基础.md\":\"856df0e0\",\"linux_实用脚本.md\":\"f2299dd5\",\"4、微服务_必备_分布式基础.md\":\"d49863d5\",\"2、数据库_redis_redis优化.md\":\"e66ae32f\",\"4、微服务_springsecurity_进阶篇.md\":\"235a8e9e\",\"5、运维_chatgpt.md\":\"10db3823\",\"2、数据库_mysql_分库分表.md\":\"e1c8a095\",\"start.md\":\"9bc1ff8d\",\"5、运维_github.md\":\"2ec6c735\",\"java学前端_css.md\":\"f11b47f0\",\"1、学前端_5、专题篇_知识篇.md\":\"a463ed8d\",\"linux_软件部署.md\":\"d6722925\",\"2、数据库_neo4j.md\":\"97ad22ac\",\"team.md\":\"ce467a6a\",\"nginx_实战篇.md\":\"7785486e\",\"index.md\":\"8c3ec167\",\"计算机基础_计算机网络_网络基础.md\":\"7a54a85d\",\"1、学前端_4、node_进阶篇.md\":\"60f6db69\",\"java_java集合.md\":\"a049b313\",\"1、学前端_3、vue_vue3_vue3高级.md\":\"614d1516\",\"1、学前端_5、小程序_微信小程序.md\":\"9a4be771\",\"5、运维_netty.md\":\"12ca0278\",\"2、数据库_mysql_mysql核心_运维.md\":\"83f97c16\",\"idea_vs code.md\":\"afdcb593\",\"java学前端_vue3_组件.md\":\"1086884e\",\"idea_chrome.md\":\"4a32afbc\",\"云原生_k8s.md\":\"db58e65a\",\"2、数据库_mysql_mysql核心_进阶.md\":\"61d16dff\",\"ssm_springbatch.md\":\"f799ab4a\",\"三高_分布式.md\":\"db1b8a1b\",\"2、数据库_elasticsearch_1、es基础.md\":\"04d17448\",\"linux_linux基础.md\":\"4b0bf394\",\"idea_idea插件.md\":\"fa86e45a\",\"可视化 _ 监控_可视化大屏.md\":\"004553bd\",\"2、数据库_mongodb_整合.md\":\"3c47d7f4\",\"4、微服务_springsecurity_基础篇.md\":\"534a3401\",\"4、微服务_进阶.md\":\"69095c58\",\"计算机基础_计算机基础_操作系统.md\":\"0f75d113\",\"可视化 _ 监控_zabbix.md\":\"71f2270e\",\"nginx_基础篇.md\":\"c7d8bb50\",\"1、学前端_4、node_项目实战.md\":\"bc5065b8\",\"2、数据库_redis_redis原理.md\":\"5cedf685\",\"可视化 _ 监控_监控基础.md\":\"ac56ce4d\",\"三高_高并发.md\":\"ea9ffc99\",\"2、数据库_redis_redis高级.md\":\"1d5872f6\",\"1、学前端_4、node_基础篇.md\":\"581cc13a\",\"2、数据库_mongodb_基础.md\":\"fb7a0a29\",\"idea_idea基础.md\":\"6f2f9638\",\"4、微服务_必备_sentinel.md\":\"2edfbf6c\",\"2、数据库_elasticsearch_3、es高级.md\":\"ef146606\",\"1、学前端_3、vue_vue3_vue3新语法.md\":\"8afd5409\",\"消息中间件_canal.md\":\"3949163c\",\"ssm_maven.md\":\"2c5e12ed\",\"4、微服务_springsecurity_高级篇.md\":\"882d3ff3\",\"linux_linux进阶.md\":\"188ef7b4\",\"计算机基础_设计模式_uml.md\":\"634ba256\",\"计算机基础_算法_leetcode.md\":\"77162fb9\",\"项目实战_小兔鲜_进阶篇1.md\":\"17c52c81\",\"1、学前端_2、js_ts_es6 基础.md\":\"fda3f18b\",\"项目实战_小兔鲜_进阶篇2.md\":\"a0f23006\",\"软件测试_测试基础.md\":\"8c1060cd\",\"2、数据库_redis_本地缓存.md\":\"00617fe6\",\"nginx_面试篇.md\":\"e3fb373a\",\"mybatis_mybatisplus_mybatis.md\":\"9239e0ad\",\"linux_shell.md\":\"ae53d83b\",\"2、数据库_mysql_mysql核心_优化.md\":\"36230425\",\"项目实战_项目推荐.md\":\"f9d97630\",\"mybatis_mybatisplus_mybatisplus.md\":\"0030fd35\",\"项目实战_百度地图_进阶篇.md\":\"c8b93267\",\"三高_高可用.md\":\"323840c5\",\"java_java新特性.md\":\"22abf56d\",\"软件测试_压力测试.md\":\"9ab44440\",\"java学前端_html_js.md\":\"e0fcd240\",\"2、数据库_redis_redis实战.md\":\"d6daeeab\",\"nginx_进阶篇.md\":\"e6b63195\",\"三高_秒杀.md\":\"3878bb64\",\"5、运维_git.md\":\"0264925c\",\"java_java进阶.md\":\"e79cb5b4\",\"并发 _ 多线程_基础篇.md\":\"7adbfac5\",\"项目实战_百度地图_基础篇.md\":\"8afa5954\",\"java学前端_react.md\":\"3ec827dd\",\"1、学前端_1、html_css_css基础.md\":\"01b56712\",\"项目实战_小兔鲜_基础篇.md\":\"646f5df5\",\"1、学前端_2、js_ts_js 基础.md\":\"cb13e36f\",\"可视化 _ 监控_监控进阶.md\":\"0cdbc292\",\"计算机基础_设计模式_基础篇.md\":\"51617287\",\"计算机基础_数据结构_基础篇.md\":\"b2bfd8d4\",\"项目实战_苍穹外卖_进阶篇.md\":\"48415e41\",\"ssm_spring.md\":\"ab514659\",\"消息中间件_rabbitmq.md\":\"45b1eb28\",\"1、学前端_1、html_css_网页进阶.md\":\"db998248\",\"消息中间件_kafka.md\":\"b747dabf\",\"云原生_docker.md\":\"983c7ba7\",\"4、微服务_必备_分布式锁.md\":\"5af1cf8d\",\"消息中间件_rocketmq.md\":\"d441da85\",\"项目实战_黑马头条_基础篇.md\":\"b05af3a6\",\"ssm_springmvc.md\":\"81b9714f\",\"项目实战_支付.md\":\"1d7407dd\",\"项目实战_黑马头条_进阶篇2.md\":\"bff0015b\",\"项目实战_黑马头条_进阶篇.md\":\"19f18388\",\"java学前端_vue2_组件.md\":\"58c6b1df\",\"3、springboot_基础篇.md\":\"529c66f4\",\"3、springboot_应用篇.md\":\"8b92aa61\",\"项目实战_黑马头条_高级篇.md\":\"227c08c1\",\"1、学前端_5、小程序_uniapp.md\":\"71a282b4\",\"项目实战_云尚办公_基础篇.md\":\"1fe188ba\",\"并发 _ 多线程_并发完善.md\":\"26619c46\",\"1、学前端_2、js_ts_js 进阶.md\":\"657dfb8f\",\"java_java高级.md\":\"23782d1a\",\"java_java基础.md\":\"86d67c77\"}");window.__VP_SITE_DATA__=JSON.parse("{\"lang\":\"en-US\",\"dir\":\"ltr\",\"title\":\"VitePress\",\"description\":\"A VitePress site\",\"base\":\"/notebook/\",\"head\":[],\"appearance\":true,\"themeConfig\":{\"algolia\":{\"appId\":\"DW7O63I9IR\",\"apiKey\":\"f8ed758cdb288a8b06542bc35923c1a1\",\"indexName\":\"notebook\"},\"sidebar\":[{\"text\":\"Java\",\"collapsed\":true,\"items\":[{\"text\":\"Java基础\",\"link\":\"/Java/Java基础\"},{\"text\":\"Java新特性\",\"link\":\"/Java/Java新特性\"},{\"text\":\"Java进阶\",\"link\":\"/Java/Java进阶\"},{\"text\":\"Java集合\",\"link\":\"/Java/Java集合\"},{\"text\":\"Java高级\",\"link\":\"/Java/Java高级\"}]},{\"text\":\"Linux\",\"collapsed\":true,\"items\":[{\"text\":\"Linux基础\",\"link\":\"/Linux/Linux基础\"},{\"text\":\"Linux新特性\",\"link\":\"/Linux/Linux进阶\"},{\"text\":\"Shell脚本\",\"link\":\"/Linux/Shell\"},{\"text\":\"实用脚本\",\"link\":\"/Linux/实用脚本\"},{\"text\":\"软件部署\",\"link\":\"/Linux/软件部署\"}]},{\"text\":\"Nginx\",\"collapsed\":true,\"items\":[{\"text\":\"基础篇\",\"link\":\"/Nginx/基础篇\"},{\"text\":\"进阶篇\",\"link\":\"/Nginx/进阶篇\"},{\"text\":\"实战篇\",\"link\":\"/Nginx/实战篇\"},{\"text\":\"面试篇\",\"link\":\"/Nginx/面试篇\"}]},{\"text\":\"SSM\",\"collapsed\":true,\"items\":[{\"text\":\"Maven\",\"link\":\"/SSM/Maven\"},{\"text\":\"Spring\",\"link\":\"/SSM/Spring\"},{\"text\":\"SpringMVC\",\"link\":\"/SSM/SpringMVC\"},{\"text\":\"SpringBatch\",\"link\":\"/SSM/SpringBatch\"}]},{\"text\":\"SpringBoot\",\"collapsed\":true,\"items\":[{\"text\":\"基础篇\",\"link\":\"/3、SpringBoot/基础篇\"},{\"text\":\"应用篇\",\"link\":\"/3、SpringBoot/应用篇\"},{\"text\":\"新特性\",\"link\":\"/3、SpringBoot/新特性\"},{\"text\":\"运维&原理\",\"link\":\"/3、SpringBoot/运维&原理\"}]},{\"text\":\"SpringCloud\",\"collapsed\":true,\"items\":[{\"text\":\"SpringCloud\",\"link\":\"/4、微服务/进阶\"},{\"text\":\"Sentinel\",\"link\":\"/4、微服务/必备/Sentinel\"}]},{\"text\":\"SpringSecurity\",\"collapsed\":true,\"items\":[{\"text\":\"SpringSecurity基础篇\",\"link\":\"/4、微服务/SpringSecurity/基础篇\"},{\"text\":\"SpringSecurity进阶篇\",\"link\":\"/4、微服务/SpringSecurity/进阶篇\"},{\"text\":\"SpringSecurity高级篇\",\"link\":\"/4、微服务/SpringSecurity/高级篇\"}]},{\"text\":\"Mybatis & MybatisPlus\",\"collapsed\":true,\"items\":[{\"text\":\"Mybatis\",\"link\":\"/Mybatis&MybatisPlus/Mybatis\"},{\"text\":\"MybatisPlus\",\"link\":\"/Mybatis&MybatisPlus/MybatisPlus\"},{\"text\":\"JPA\",\"link\":\"/Mybatis&MybatisPlus/JPA\"}]},{\"text\":\"Git & ChatGPT\",\"collapsed\":true,\"items\":[{\"text\":\"Git\",\"link\":\"/5、运维/Git\"},{\"text\":\"Github\",\"link\":\"/5、运维/Github\"},{\"text\":\"ChatGPT\",\"link\":\"/5、运维/ChatGPT\"},{\"text\":\"Jenkins\",\"link\":\"/5、运维/Jenkins\"},{\"text\":\"Netty\",\"link\":\"/5、运维/Netty\"}]},{\"text\":\"数据库\",\"collapsed\":true,\"items\":[{\"text\":\"MySQL\",\"collapsed\":true,\"items\":[{\"text\":\"MySQL基础\",\"link\":\"/2、数据库/MySQL/MySQL核心/基础\"},{\"text\":\"MySQL进阶\",\"link\":\"/2、数据库/MySQL/MySQL核心/进阶\"},{\"text\":\"MySQL优化\",\"link\":\"/2、数据库/MySQL/MySQL核心/优化\"},{\"text\":\"MySQL设计\",\"link\":\"/2、数据库/MySQL/MySQL核心/设计\"},{\"text\":\"MySQL运维\",\"link\":\"/2、数据库/MySQL/MySQL核心/运维\"},{\"text\":\"分库分表\",\"link\":\"/2、数据库/MySQL/分库分表\"}]},{\"text\":\"Redis\",\"collapsed\":true,\"items\":[{\"text\":\"Redis基础\",\"link\":\"/2、数据库/Redis/Redis基础\"},{\"text\":\"Redis优化\",\"link\":\"/2、数据库/Redis/Redis优化\"},{\"text\":\"Redis原理\",\"link\":\"/2、数据库/Redis/Redis原理\"},{\"text\":\"Redis高级\",\"link\":\"/2、数据库/Redis/Redis高级\"},{\"text\":\"Redis实战\",\"link\":\"/2、数据库/Redis/Redis实战\"},{\"text\":\"本地缓存\",\"link\":\"/2、数据库/Redis/本地缓存\"}]},{\"text\":\"MongoDB\",\"collapsed\":true,\"items\":[{\"text\":\"MongoDB基础\",\"link\":\"/2、数据库/MongoDB/基础\"},{\"text\":\"MongoDB进阶\",\"link\":\"/2、数据库/MongoDB/整合\"}]},{\"text\":\"ElasticSearch\",\"collapsed\":true,\"items\":[{\"text\":\"ES基础\",\"link\":\"/2、数据库/ElasticSearch/1、ES基础\"},{\"text\":\"ES高级\",\"link\":\"/2、数据库/ElasticSearch/3、ES高级\"}]},{\"text\":\"InfluxDB\",\"link\":\"/2、数据库/influxdb\"},{\"text\":\"Neo4j\",\"link\":\"/2、数据库/Neo4j\"}]},{\"text\":\"高并发 & 秒杀 & 分布式\",\"collapsed\":true,\"items\":[{\"text\":\"分布式理论\",\"link\":\"/三高/分布式\"},{\"text\":\"分布式锁\",\"link\":\"/4、微服务/必备/分布式锁\"},{\"text\":\"秒杀\",\"link\":\"/三高/秒杀\"},{\"text\":\"高可用\",\"link\":\"/三高/高可用\"},{\"text\":\"高并发\",\"link\":\"/三高/高并发\"}]},{\"text\":\"云原生\",\"collapsed\":true,\"items\":[{\"text\":\"Docker\",\"link\":\"/云原生/Docker\"},{\"text\":\"K8S\",\"link\":\"/云原生/K8S\"}]},{\"text\":\"可视化 & 监控\",\"collapsed\":true,\"items\":[{\"text\":\"监控基础\",\"link\":\"/可视化 & 监控/监控基础\"},{\"text\":\"监控进阶\",\"link\":\"/可视化 & 监控/监控进阶\"},{\"text\":\"可视化大屏\",\"link\":\"/可视化 & 监控/可视化大屏\"},{\"text\":\"Zabbix\",\"link\":\"/可视化 & 监控/Zabbix\"}]},{\"text\":\"学前端\",\"collapsed\":true,\"items\":[{\"text\":\"HTML+CSS\",\"collapsed\":true,\"items\":[{\"text\":\"HTML基础\",\"link\":\"/1、学前端/1、HTML+CSS/HTML基础\"},{\"text\":\"CSS基础\",\"link\":\"/1、学前端/1、HTML+CSS/CSS基础\"},{\"text\":\"网页进阶\",\"link\":\"/1、学前端/1、HTML+CSS/网页进阶\"}]},{\"text\":\"JS+TS\",\"collapsed\":true,\"items\":[{\"text\":\"JS基础\",\"link\":\"/1、学前端/2、JS+TS/JS 基础\"},{\"text\":\"JS进阶\",\"link\":\"/1、学前端/2、JS+TS/JS 进阶\"},{\"text\":\"ES6基础\",\"link\":\"/1、学前端/2、JS+TS/ES6 基础\"},{\"text\":\"ES6进阶\",\"link\":\"/1、学前端/2、JS+TS/ES6 进阶\"},{\"text\":\"TS基础\",\"link\":\"/1、学前端/2、JS+TS/TypeScript\"}]},{\"text\":\"NodeJS\",\"collapsed\":true,\"items\":[{\"text\":\"Node基础\",\"link\":\"/1、学前端/4、Node/基础篇\"},{\"text\":\"Node进阶\",\"link\":\"/1、学前端/4、Node/进阶篇\"},{\"text\":\"项目实战\",\"link\":\"/1、学前端/4、Node/项目实战\"}]},{\"text\":\"Vue\",\"collapsed\":true,\"items\":[{\"text\":\"Vue3进阶\",\"link\":\"/1、学前端/3、Vue/Vue3/Vue3进阶\"},{\"text\":\"Vue3高级\",\"link\":\"/1、学前端/3、Vue/Vue3/Vue3高级\"},{\"text\":\"Vue3新语法\",\"link\":\"/1、学前端/3、Vue/Vue3/Vue3新语法\"},{\"text\":\"项目实战\",\"link\":\"/1、学前端/3、Vue/Vue2/Vue2项目\"}]},{\"text\":\"小程序\",\"collapsed\":true,\"items\":[{\"text\":\"小程序基础\",\"link\":\"/1、学前端/5、小程序/微信小程序\"},{\"text\":\"小程序优化\",\"link\":\"/1、学前端/5、小程序/小程序优化\"},{\"text\":\"uniapp\",\"link\":\"/1、学前端/5、小程序/uniapp\"},{\"text\":\"项目实战\",\"link\":\"/1、学前端/5、小程序/小程序项目\"}]}]},{\"text\":\"计算机基础\",\"collapsed\":true,\"items\":[{\"text\":\"数据结构\",\"link\":\"/计算机基础/数据结构/基础篇\"},{\"text\":\"操作系统\",\"link\":\"/计算机基础/计算机基础/操作系统\"},{\"text\":\"设计模式\",\"link\":\"/计算机基础/设计模式/基础篇\"},{\"text\":\"计算机网络\",\"link\":\"/计算机基础/计算机网络/网络基础\"},{\"text\":\"UML\",\"link\":\"/计算机基础/设计模式/UML\"},{\"text\":\"LeetCode\",\"link\":\"/计算机基础/算法/LeetCode\"}]},{\"text\":\"项目实战\",\"collapsed\":true,\"items\":[{\"text\":\"云尚办公\",\"collapsed\":true,\"items\":[{\"text\":\"基础篇\",\"link\":\"/项目实战/云尚办公/基础篇\"}]},{\"text\":\"小兔鲜\",\"collapsed\":true,\"items\":[{\"text\":\"基础篇\",\"link\":\"/项目实战/小兔鲜/基础篇\"},{\"text\":\"进阶篇1\",\"link\":\"/项目实战/小兔鲜/进阶篇1\"},{\"text\":\"进阶篇2\",\"link\":\"/项目实战/小兔鲜/进阶篇2\"}]},{\"text\":\"地图\",\"collapsed\":true,\"items\":[{\"text\":\"基础篇\",\"link\":\"/项目实战/百度地图/基础篇\"},{\"text\":\"进阶篇\",\"link\":\"/项目实战/百度地图/进阶篇\"}]},{\"text\":\"苍穹外卖\",\"collapsed\":true,\"items\":[{\"text\":\"进阶篇\",\"link\":\"/项目实战/苍穹外卖/进阶篇\"}]},{\"text\":\"黑马头条\",\"collapsed\":true,\"items\":[{\"text\":\"基础篇\",\"link\":\"/项目实战/黑马头条/基础篇\"},{\"text\":\"进阶篇\",\"link\":\"/项目实战/黑马头条/进阶篇\"},{\"text\":\"进阶篇2\",\"link\":\"/项目实战/黑马头条/进阶篇2\"},{\"text\":\"高级篇\",\"link\":\"/项目实战/黑马头条/高级篇\"}]},{\"text\":\"支付\",\"link\":\"/项目实战/支付\"},{\"text\":\"项目推荐\",\"link\":\"/项目实战/项目推荐\"}]},{\"text\":\"团队成员\",\"link\":\"/team\"}],\"siteTitle\":\"任硕的文档\",\"logo\":\"/Vue.png\",\"nav\":[{\"text\":\"Java学前端\",\"items\":[{\"items\":[{\"text\":\"HTML+JS\",\"link\":\"/Java学前端/HTML+JS\"},{\"text\":\"CSS\",\"link\":\"/Java学前端/CSS\"},{\"text\":\"Vue2+组件\",\"link\":\"/Java学前端/Vue2+组件\"},{\"text\":\"Vue3+组件\",\"link\":\"/Java学前端/Vue3+组件\"},{\"text\":\"React\",\"link\":\"/Java学前端/React\"}]}],\"activeMatch\":\"/Java/\"},{\"text\":\"软件测试\",\"items\":[{\"items\":[{\"text\":\"测试基础\",\"link\":\"/软件测试/测试基础\"},{\"text\":\"压力测试\",\"link\":\"/软件测试/压力测试\"}]}]},{\"text\":\"多线程\",\"items\":[{\"items\":[{\"text\":\"基础篇\",\"link\":\"/并发 & 多线程/基础篇\"},{\"text\":\"进阶篇\",\"link\":\"/并发 & 多线程/并发完善\"}]}]},{\"text\":\"开发工具\",\"items\":[{\"items\":[{\"text\":\"Chrome\",\"link\":\"/IDEA/Chrome\"},{\"text\":\"IDEA基础\",\"link\":\"/IDEA/IDEA基础\"},{\"text\":\"IDEA插件\",\"link\":\"/IDEA/IDEA插件\"},{\"text\":\"VS Code\",\"link\":\"/IDEA/VS Code\"}]}]},{\"text\":\"消息中间件\",\"items\":[{\"items\":[{\"text\":\"RabbitMQ\",\"link\":\"/消息中间件/RabbitMQ\"},{\"text\":\"RocketMQ\",\"link\":\"/消息中间件/RocketMQ\"},{\"text\":\"Kafka\",\"link\":\"/消息中间件/Kafka\"},{\"text\":\"Canal\",\"link\":\"/消息中间件/Canal\"}]}]}],\"socialLinks\":[{\"icon\":\"github\",\"link\":\"https://github.com/renshuo123/renshuo123.github.io\"},{\"icon\":\"twitter\",\"link\":\"#\"},{\"icon\":{\"svg\":\"<svg t=\\\"1676028692954\\\" class=\\\"icon\\\" ...</path></svg>\"},\"link\":\"https://github.com/\"}]},\"locales\":{},\"scrollOffset\":90,\"cleanUrls\":false}");</script>
    
  </body>
</html>